﻿Перем РезультатыСравненияТаблиц Экспорт;
Перем СтатусыРезультатаТестирования Экспорт;
Перем ПараметрыОтчетаУФ;
Перем ОтчетВРежимеУФ;
Перем ЭтоLinux;


Функция ПолучитьВерсиюОбработки(ДобавлятьНазвание = Истина,ТолькоЦифры = Ложь) Экспорт
	Версия = "1.000";
	
	Если ТолькоЦифры Тогда
		Возврат Версия;	
	КонецЕсли;	 
	
	Если ДобавлятьНазвание Тогда
		Возврат "vanessa-behavior ver " + Версия;	
	КонецЕсли;  
	
	Возврат "ver " + Версия;	
КонецФункции

Функция Транслит(Стр) Экспорт
    Рез = СокрЛП(Стр);   
    Рез = СтрЗаменить(Рез,"а","a");
    Рез = СтрЗаменить(Рез,"б","b");
    Рез = СтрЗаменить(Рез,"в","v");
    Рез = СтрЗаменить(Рез,"г","g");
    Рез = СтрЗаменить(Рез,"д","d");
    Рез = СтрЗаменить(Рез,"е","e");
    Рез = СтрЗаменить(Рез,"ё","e");
    Рез = СтрЗаменить(Рез,"ж","zh");
    Рез = СтрЗаменить(Рез,"з","z");
    Рез = СтрЗаменить(Рез,"и","i");
    Рез = СтрЗаменить(Рез,"к","k");
    Рез = СтрЗаменить(Рез,"л","l");
    Рез = СтрЗаменить(Рез,"м","m");
    Рез = СтрЗаменить(Рез,"н","n");
    Рез = СтрЗаменить(Рез,"о","o");
    Рез = СтрЗаменить(Рез,"п","p");
    Рез = СтрЗаменить(Рез,"р","r");
    Рез = СтрЗаменить(Рез,"с","s");
    Рез = СтрЗаменить(Рез,"т","t");
    Рез = СтрЗаменить(Рез,"у","u");
    Рез = СтрЗаменить(Рез,"ф","f");
    Рез = СтрЗаменить(Рез,"х","h");
    Рез = СтрЗаменить(Рез,"ч","ch");
    Рез = СтрЗаменить(Рез,"ш","sh");
    Рез = СтрЗаменить(Рез,"щ","sch");
    Рез = СтрЗаменить(Рез,"ъ","");
    Рез = СтрЗаменить(Рез,"ь","");
    Рез = СтрЗаменить(Рез,"э","e");
    Рез = СтрЗаменить(Рез,"ю","yu");
    Рез = СтрЗаменить(Рез,"й","i");
    Рез = СтрЗаменить(Рез,"ц","c");
    Рез = СтрЗаменить(Рез,"я","ya");
    Рез = СтрЗаменить(Рез,"ы","i");
    Рез = СтрЗаменить(Рез,"А","A");
    Рез = СтрЗаменить(Рез,"Б","B");
    Рез = СтрЗаменить(Рез,"В","V");
    Рез = СтрЗаменить(Рез,"Г","G");
    Рез = СтрЗаменить(Рез,"Д","D");
    Рез = СтрЗаменить(Рез,"Е","E");
    Рез = СтрЗаменить(Рез,"Ё","E");
    Рез = СтрЗаменить(Рез,"Ж","ZH");
    Рез = СтрЗаменить(Рез,"З","Z");
    Рез = СтрЗаменить(Рез,"И","I");
    Рез = СтрЗаменить(Рез,"К","K");
    Рез = СтрЗаменить(Рез,"Л","L");
    Рез = СтрЗаменить(Рез,"М","M");
    Рез = СтрЗаменить(Рез,"Н","N");
    Рез = СтрЗаменить(Рез,"О","O");
    Рез = СтрЗаменить(Рез,"П","P");
    Рез = СтрЗаменить(Рез,"Р","R");
    Рез = СтрЗаменить(Рез,"С","S");
    Рез = СтрЗаменить(Рез,"Т","T");
    Рез = СтрЗаменить(Рез,"У","U");
    Рез = СтрЗаменить(Рез,"Ф","F");
    Рез = СтрЗаменить(Рез,"Х","H");
    Рез = СтрЗаменить(Рез,"Ч","CH");
    Рез = СтрЗаменить(Рез,"Ш","SH");
    Рез = СтрЗаменить(Рез,"Щ","SCH");
    Рез = СтрЗаменить(Рез,"Ъ","");
    Рез = СтрЗаменить(Рез,"Ь","");
    Рез = СтрЗаменить(Рез,"Ы","I");
    Рез = СтрЗаменить(Рез,"Ц","C");
    Рез = СтрЗаменить(Рез,"Э","E");
    Рез = СтрЗаменить(Рез,"Ю","YU");
    Рез = СтрЗаменить(Рез,"Я","YA");
    Рез = СтрЗаменить(Рез,"Й","I");
    Возврат(Рез);
КонецФункции

Процедура СделатьСообщение(Знач Сообщение, ТипСообщения = "Информация") Экспорт
	
	ТипСообщения = ?(ТипСообщения = "Информация", СтатусСообщения.Обычное, СтатусСообщения.ОченьВажное);
	
	Если ДелатьСообщенияТранслитом Тогда
		Сообщение = Транслит(Сообщение);
	КонецЕсли;	 
	
	Сообщить(Строка(ТекущаяДата()) + " " + Сообщение, ТипСообщения);
КонецПроцедуры

Процедура Отладка(Знач Сообщение) Экспорт
	Если DebugLog Тогда
		СделатьСообщение(Сообщение);
	КонецЕсли; 
КонецПроцедуры

Функция ДополнитьСлешВПуть(Знач Каталог)
	разделитель = "\";

	Если ЭтоLinux Тогда
		разделитель = "/";
	КонецЕсли;
	
	Если Найти(Прав(Каталог, 1), "\/") > 0 Тогда 
		Каталог = Лев(Каталог,СтрДлина(Каталог)-1);
	КонецЕсли;
	
	Если Прав(Каталог, 1) <> разделитель Тогда
		Каталог = Каталог + разделитель;
	КонецЕсли;
	
	Возврат Каталог;
	
КонецФункции


//{Отчет Allure

Процедура ЗаписатьСтатусВШагИлиСценарий(ОбъектДляЗаписи,Статус)
	Если Статус = "Success" Тогда
		ОбъектДляЗаписи.status = "passed";
	ИначеЕсли Статус = "Pending" Тогда
		ОбъектДляЗаписи.status = "pending";
	ИначеЕсли Статус = "Failed" Тогда
		ОбъектДляЗаписи.status = "failed";
	ИначеЕсли Статус = "Skipped" Тогда
		ОбъектДляЗаписи.status = "skipped";
	Иначе	
		ОбъектДляЗаписи.status = "skipped";
	КонецЕсли; 
	

КонецПроцедуры

Процедура ДобавитьПрефиксAllureВСтроку(Стр)
	Стр = СтрЗаменить(Стр,"<test-suite-result","<ns2:test-suite");
	Стр = СтрЗаменить(Стр,"</test-suite-result>","</ns2:test-suite>");
	Стр = СтрЗаменить(Стр,"xmlns=""urn:model.allure.qatools.yandex.ru""","xmlns:ns2=""urn:model.allure.qatools.yandex.ru""");
КонецПроцедуры

Процедура ДобавитьМетку(Фабрика,СписокМеток,name,value)
	Типlabel    = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "label");
	Метка       = Фабрика.Создать(Типlabel);
	Метка.name  = name;
	Метка.value = value;
	
	СписокМеток.label.Добавить(Метка);
КонецПроцедуры

Функция УбратьСимволыДляКорректногоОтчетаAllure(Знач Стр)
	Стр = СтрЗаменить(Стр,".","_");
	Возврат Стр;
КонецФункции	

Функция ПолучитьПрефиксИмениСценария()
	Если ЗначениеЗаполнено(ИмяТекущейСборки) Тогда
		Возврат "(" + УбратьСимволыДляКорректногоОтчетаAllure(ИмяТекущейСборки) + ") ";
	КонецЕсли;	 
	
	Возврат "";
	
	//СисИнфо          = Новый СистемнаяИнформация;
	//ВерсияПриложения = СисИнфо.ВерсияПриложения;
	//
	//ВерсияПриложения = СтрЗаменить(ВерсияПриложения,".","-");
	//
	//ТипФорм = "OF";
	//Если ОтчетВРежимеУФ Тогда
	//	ТипФорм = "UF";
	//	Если ПараметрыОтчетаУФ.ЕстьПоддержкаАсинхронныхВызовов Тогда
	//		ТипФорм = "UF" + "_NoSync";
	//	КонецЕсли;	 
	//КонецЕсли;
	//
	//Возврат "(" + ВерсияПриложения + "_" + ТипФорм + ") ";
КонецФункции	

Процедура ОбойтиДеревоДляОтчетаАллюр(Дерево,Фабрика,ТекущаяФича = Неопределено,СписокСценариев = Неопределено,СписокШагов = Неопределено)
	Для каждого СтрСтроки Из Дерево.Строки Цикл
		Если      СтрСтроки.Фича = Истина Тогда
			
			GUID             = Новый УникальныйИдентификатор();
			РеальноеИмяФайла = "" + GUID +"-testsuite.xml";
			ИмяФайлаXML      = ДополнитьСлешВПуть(КаталогOutputAllure) + РеальноеИмяФайла;
			
			Если ОтчетВРежимеУФ Тогда
				СтруткутаДляФайлаXML = Новый Структура;
				СтруткутаДляФайлаXML.Вставить("РеальноеИмяФайла",РеальноеИмяФайла);
				
				ИмяФайлаXML = ПолучитьИмяВременногоФайла("xml");
			КонецЕсли;	 
			
			ЗТ = Новый ЗаписьТекста(ИмяФайлаXML, КодировкаТекста.ANSI);
			ЗТ.Закрыть();
			
			ВременныйФайлXML = ПолучитьИмяВременногоФайла("xml");
			ЗаписьXML = Новый ЗаписьXML;
			
			ЗаписьXML.ОткрытьФайл(ВременныйФайлXML);			
			ЗаписьXML.ЗаписатьОбъявлениеXML();
			
			ТипTestSuiteResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-suite-result");
			ТекущаяФича        = Фабрика.Создать(ТипTestSuiteResult);
			ТекущаяФича.name   = СтрСтроки.Имя;
			
			ТипTestCasesResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-cases-result");
			СписокСценариев    = Фабрика.Создать(ТипTestCasesResult);
			
			ОбойтиДеревоДляОтчетаАллюр(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
			
			ТекущаяФича.test_cases = СписокСценариев;
			
			
			Типlabels   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "labels");
			СписокМеток = Фабрика.Создать(Типlabels);
			
			ДобавитьМетку(Фабрика,СписокМеток,"feature",СтрСтроки.Имя);
			ДобавитьМетку(Фабрика,СписокМеток,"framework","vanessa-behavior");
			ДобавитьМетку(Фабрика,СписокМеток,"language","1С");
			
			
			ТекущаяФича.labels = СписокМеток;
			
			Фабрика.ЗаписатьXML(ЗаписьXML, ТекущаяФича);
			ЗаписьXML.Закрыть();
			
			
			//делаем запись без BOM и немного преобразуем строки xml
			ЗТ = Новый ЗаписьТекста(ИмяФайлаXML,,, Истина);
			Текст = Новый ЧтениеТекста;
			Текст.Открыть(ВременныйФайлXML,"UTF-8");
			
			Пока Истина Цикл
				Стр = Текст.ПрочитатьСтроку();
				Если Стр = Неопределено Тогда
					Прервать;
				КонецЕсли;	 
				ДобавитьПрефиксAllureВСтроку(Стр);
				
				ЗТ.ЗаписатьСтроку(Стр);
			КонецЦикла;	
			ЗТ.Закрыть();
			Текст.Закрыть();
			 
			
			Если ОтчетВРежимеУФ Тогда
				ДвоичныеДанные = Новый ДвоичныеДанные(ИмяФайлаXML);
				СтруткутаДляФайлаXML.Вставить("ФайлXMLДвоичныеДанные",ДвоичныеДанные);
				ПараметрыОтчетаУФ.МассивXMLОтчетаAllure.Добавить(СтруткутаДляФайлаXML);
				
				УдалитьФайлы(ИмяФайлаXML);
			Иначе	
				СделатьСообщение("Файл отчета Allure-report (" + ИмяФайлаXML + ") записан.");
			КонецЕсли;	 
			
			
		ИначеЕсли (СтрСтроки.Сценарий = Истина) или (СтрСтроки.Пример = Истина) Тогда
			Если (СтрСтроки.ЭтоКонтекст = Истина) Тогда
				//его не неадо добавлять в отчет, т.к. этот сценарий включается в каждый сценарий
				
			ИначеЕсли (СтрСтроки.ЭтоScenarioOutline = Истина) или (СтрСтроки.Строки.Количество() = 0) Тогда
				//его не неадо добавлять в отчет, т.к. этот сценарий явно не выполняется
				ОбойтиДеревоДляОтчетаАллюр(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
			Иначе
				
				ЕстьДанныеПоСценарию = Истина;
				
				Если ОтчетВРежимеУФ Тогда
					ИДВМассиве                         = ПараметрыОтчетаУФ.МассивИДСтрокиДерева.Найти(СтрСтроки.ИДСтроки);
					Если ИДВМассиве = Неопределено Тогда
						ЕстьДанныеПоСценарию = Ложь;
					Иначе	
						РезультатПрохожденияТестовСценария = ПараметрыОтчетаУФ.МассивРезультатПрохожденияТестовСценария[ИДВМассиве];
					КонецЕсли;	 
					
				Иначе	
					РезультатПрохожденияТестовСценария = СтрСтроки.РезультатПрохожденияТестовСценария;
				КонецЕсли;	 
				
				
				
				Если ЕстьДанныеПоСценарию  Тогда
					
					ТипTestCaseResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-case-result");
					Сценарий          = Фабрика.Создать(ТипTestCaseResult);
					
					ПрефиксИмениСценария = "";
					Если ДобавлятьКИмениСценарияУловияВыгрузки Тогда
						ПрефиксИмениСценария = ПолучитьПрефиксИмениСценария();
					КонецЕсли;	 
					
					Если СтрСтроки.Пример = Истина Тогда
						Сценарий.name     = ПрефиксИмениСценария + СтрСтроки.Родитель.Родитель.Имя + " №" + (СтрСтроки.Родитель.Строки.Индекс(СтрСтроки));
					Иначе	
						Сценарий.name     = ПрефиксИмениСценария + СтрСтроки.Имя;
					КонецЕсли; 
					
					Сценарий.start = РезультатПрохожденияТестовСценария.ВремяНачала;
					Сценарий.stop  = РезультатПрохожденияТестовСценария.ВремяОкончания;
					
					
					ТипSteps    = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "steps");
					СписокШагов = Фабрика.Создать(ТипSteps);
					
					
					
					Если СтрСтроки.ЭтоScenarioOutline = Истина Тогда
						ОбойтиДеревоДляОтчетаАллюр(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
					Иначе
						Для каждого СтрРезультатПрохожденияТестовШагов Из РезультатПрохожденияТестовСценария.РезультатПрохожденияТестовШагов Цикл
							ТипStep   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "step");
							Шаг       = Фабрика.Создать(ТипStep);
							Шаг.name  = СтрРезультатПрохожденияТестовШагов.Имя;
							Шаг.title = СтрРезультатПрохожденияТестовШагов.Имя;
							
							Если СтрРезультатПрохожденияТестовШагов.ВремяНачала <> Неопределено Тогда
								Шаг.start = СтрРезультатПрохожденияТестовШагов.ВремяНачала;
								Шаг.stop  = СтрРезультатПрохожденияТестовШагов.ВремяОкончания;
							КонецЕсли; 
							
							ЗаписатьСтатусВШагИлиСценарий(Шаг,СтрРезультатПрохожденияТестовШагов.Статус);
							
							СписокШагов.step.Добавить(Шаг);
						КонецЦикла;
					КонецЕсли;	 
					
					
					
					
					ЗаписатьСтатусВШагИлиСценарий(Сценарий,СтрСтроки.Статус);
					Если (СтрСтроки.Статус = "Failed") или (СтрСтроки.Статус = "Pending") Тогда
						ТипFailure            = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "failure");
						ОбъектFailure         = Фабрика.Создать(ТипFailure);
						ОбъектFailure.message = РезультатПрохожденияТестовСценария.ОписаниеОшибки;
						
						Сценарий.failure = ОбъектFailure;
					КонецЕсли; 
					Сценарий.steps = СписокШагов;
					
					
					Если РезультатПрохожденияТестовСценария.Свойство("МассивСкриншотов") Тогда
						//значит есть скриншоты
						
						Типattachments    = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "attachments");
						Списокattachments = Фабрика.Создать(Типattachments);
						
						Для каждого СтруктураСкриншот Из РезультатПрохожденияТестовСценария.МассивСкриншотов Цикл
							Типattachment  = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "attachment");
							attachment      = Фабрика.Создать(Типattachment);
							
							attachment.title  = "screenshot";
							attachment.source = СтруктураСкриншот.ИмяФайла;
							
							Списокattachments.attachment.Добавить(attachment);
						КонецЦикла;
						Сценарий.attachments = Списокattachments;
					КонецЕсли;	 
					
					
					Типlabels   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "labels");
					СписокМеток = Фабрика.Создать(Типlabels);
					ДобавитьМетку(Фабрика,СписокМеток,"story",СтрСтроки.Имя);
					Сценарий.labels = СписокМеток;
					
					
					
					СписокСценариев.test_case.Добавить(Сценарий);
					//Сообщить(СтрСтроки.Имя);
				КонецЕсли;	 
			КонецЕсли; 
		ИначеЕсли СтрСтроки.Шаг = Истина Тогда
			Если СтрСтроки.Родитель.ЭтоScenarioOutline = Истина Тогда
				//его не неадо добавлять в отчет, т.к. этот сценарий явно не выполняется
				ОбойтиДеревоДляОтчетаАллюр(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
			Иначе	
				ТипStep   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "step");
				Шаг       = Фабрика.Создать(ТипStep);
				Шаг.name  = СтрСтроки.Имя;
				Шаг.title = СтрСтроки.Имя;
				
				Если СтрСтроки.ВремяНачала <> Неопределено Тогда
					Шаг.start = СтрСтроки.ВремяНачала;
					Шаг.stop  = СтрСтроки.ВремяОкончания;
				КонецЕсли; 
				
				ЗаписатьСтатусВШагИлиСценарий(Шаг,СтрСтроки.Статус);
				СписокШагов.step.Добавить(Шаг);
			КонецЕсли; 
		Иначе	
			ОбойтиДеревоДляОтчетаАллюр(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
		КонецЕсли; 
	КонецЦикла;
КонецПроцедуры

Процедура СформироватьОтчетАллюр(СтруктураОФ = Неопределено) Экспорт
	Перем СтарыйКаталог, ИмяФайла;
	СтарыйКаталог = КаталогOutputAllure;
	
	ОтчетВРежимеУФ = Ложь;
	
	Если СтруктураОФ = Неопределено Тогда
		ИмяФайла     = КаталогИнструментов + "/vendor/allure-framework/allure.xsd"; 
	Иначе	
		ОтчетВРежимеУФ = Истина;
		ПараметрыОтчетаУФ    = СтруктураОФ;
		
		ИмяФайла = ПолучитьИмяВременногоФайла("xsd");
	    СхемаAllure = СтруктураОФ.СхемаAllure;
		СхемаAllure.Записать(ИмяФайла);
	
		МассивXMLОтчетаAllure = Новый Массив;
		СтруктураОФ.Вставить("МассивXMLОтчетаAllure",МассивXMLОтчетаAllure);
		
		ПутьКВременномуКаталогуНаСервере = КаталогВременныхФайлов() + Лев(Строка(Новый УникальныйИдентификатор), 8);
		СоздатьКаталог(ПутьКВременномуКаталогуНаСервере);
		
		КаталогOutputAllure = ПутьКВременномуКаталогуНаСервере;
		
	КонецЕсли;	 
	
	Файл = Новый Файл(КаталогOutputAllure);
	Если Не Файл.Существует() Тогда
		СделатьСообщение("Не могу сфомировать отчет Allure. Не существует каталог для вывода отчета.");
		Возврат;
	КонецЕсли; 

	
	Фабрика      = СоздатьФабрикуXDTO(ИмяФайла);
	
	//ТипTestSuiteResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-suite-result");
	//СписокФич          = Фабрика.Создать(ТипTestSuiteResult);
	
	//ЗаписьXML = Новый ЗаписьXML;
	КаталогOutputAllure = ДополнитьСлешВПуть(КаталогOutputAllure);
	
	//ЗаписьXML.ОткрытьФайл(КаталогOutputAllure + "\AllureReport.xml");
	
	ОбойтиДеревоДляОтчетаАллюр(ДеревоТестов, Фабрика);
	
	КаталогOutputAllure = СтарыйКаталог;
	//ДанныеXML = ЗаписьXML.Закрыть();	
	
КонецПроцедуры

//}Отчет Allure


//{Отчет xUnit

Процедура ОбойтиДеревоДляОтчетаxUnit(Дерево, Фабрика, ТекущаяФича = Неопределено,СписокСценариев = Неопределено,СписокШагов = Неопределено)
	Для каждого СтрСтроки Из Дерево.Строки Цикл
		Если      СтрСтроки.Фича = Истина Тогда
			
			GUID             = Новый УникальныйИдентификатор();
			РеальноеИмяФайла = "" + GUID +"-testsuite.xml";
			ИмяФайлаXML      = ДополнитьСлешВПуть(КаталогOutputxUnit) + РеальноеИмяФайла;
			
			Если ОтчетВРежимеУФ Тогда
				СтруткутаДляФайлаXML = Новый Структура;
				СтруткутаДляФайлаXML.Вставить("РеальноеИмяФайла",РеальноеИмяФайла);
				
				ИмяФайлаXML = ПолучитьИмяВременногоФайла("xml");
			КонецЕсли;	 
			
			ЗТ = Новый ЗаписьТекста(ИмяФайлаXML, КодировкаТекста.ANSI);
			ЗТ.Закрыть();
			
			ВременныйФайлXML = ПолучитьИмяВременногоФайла("xml");
			ЗаписьXML = Новый ЗаписьXML;
			
			ЗаписьXML.ОткрытьФайл(ВременныйФайлXML);			
			ЗаписьXML.ЗаписатьОбъявлениеXML();
			
			ТипTestSuiteResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-suite-result");
			ТекущаяФича        = Фабрика.Создать(ТипTestSuiteResult);
			ТекущаяФича.name   = СтрСтроки.Имя;
			
			ТипTestCasesResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-cases-result");
			СписокСценариев    = Фабрика.Создать(ТипTestCasesResult);
			
			ОбойтиДеревоДляОтчетаxUnit(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
			
			ТекущаяФича.test_cases = СписокСценариев;
			
			
			Типlabels   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "labels");
			СписокМеток = Фабрика.Создать(Типlabels);
			
			ДобавитьМетку(Фабрика,СписокМеток,"feature",СтрСтроки.Имя);
			ДобавитьМетку(Фабрика,СписокМеток,"framework","vanessa-behavior");
			ДобавитьМетку(Фабрика,СписокМеток,"language","1С");
			
			
			ТекущаяФича.labels = СписокМеток;
			
			Фабрика.ЗаписатьXML(ЗаписьXML, ТекущаяФича);
			ЗаписьXML.Закрыть();
			
			
			//делаем запись без BOM и немного преобразуем строки xml
			ЗТ = Новый ЗаписьТекста(ИмяФайлаXML,,, Истина);
			Текст = Новый ЧтениеТекста;
			Текст.Открыть(ВременныйФайлXML,"UTF-8");
			
			Пока Истина Цикл
				Стр = Текст.ПрочитатьСтроку();
				Если Стр = Неопределено Тогда
					Прервать;
				КонецЕсли;	 
				ДобавитьПрефиксAllureВСтроку(Стр);
				
				ЗТ.ЗаписатьСтроку(Стр);
			КонецЦикла;	
			ЗТ.Закрыть();
			Текст.Закрыть();
			 
			
			Если ОтчетВРежимеУФ Тогда
				ДвоичныеДанные = Новый ДвоичныеДанные(ИмяФайлаXML);
				СтруткутаДляФайлаXML.Вставить("ФайлXMLДвоичныеДанные",ДвоичныеДанные);
				ПараметрыОтчетаУФ.МассивXMLОтчетаxUnit.Добавить(СтруткутаДляФайлаXML);
				
				УдалитьФайлы(ИмяФайлаXML);
			Иначе	
				СделатьСообщение("Файл отчета (" + ИмяФайлаXML + ") записан.");
			КонецЕсли;	 
			
			
		ИначеЕсли (СтрСтроки.Сценарий = Истина) или (СтрСтроки.Пример = Истина) Тогда
			Если (СтрСтроки.ЭтоКонтекст = Истина) Тогда
				//его не неадо добавлять в отчет, т.к. этот сценарий включается в каждый сценарий
				
			ИначеЕсли (СтрСтроки.ЭтоScenarioOutline = Истина) или (СтрСтроки.Строки.Количество() = 0) Тогда
				//его не неадо добавлять в отчет, т.к. этот сценарий явно не выполняется
				ОбойтиДеревоДляОтчетаxUnit(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
			Иначе
				
				
				Если ОтчетВРежимеУФ Тогда
					ИДВМассиве                         = ПараметрыОтчетаУФ.МассивИДСтрокиДерева.Найти(СтрСтроки.ИДСтроки);
					РезультатПрохожденияТестовСценария = ПараметрыОтчетаУФ.МассивРезультатПрохожденияТестовСценария[ИДВМассиве];
				Иначе	
					РезультатПрохожденияТестовСценария = СтрСтроки.РезультатПрохожденияТестовСценария;
				КонецЕсли;	 
				
				ТипTestCaseResult = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "test-case-result");
				Сценарий          = Фабрика.Создать(ТипTestCaseResult);
				
				ПрефиксИмениСценария = "";
				Если ДобавлятьКИмениСценарияУловияВыгрузки Тогда
					ПрефиксИмениСценария = ПолучитьПрефиксИмениСценария();
				КонецЕсли;	 
				
				Если СтрСтроки.Пример = Истина Тогда
					Сценарий.name     = ПрефиксИмениСценария + СтрСтроки.Родитель.Родитель.Имя + " №" + (СтрСтроки.Родитель.Строки.Индекс(СтрСтроки));
				Иначе	
					Сценарий.name     = ПрефиксИмениСценария + СтрСтроки.Имя;
				КонецЕсли; 
				
				Сценарий.start = РезультатПрохожденияТестовСценария.ВремяНачала;
				Сценарий.stop  = РезультатПрохожденияТестовСценария.ВремяОкончания;
				
				
				ТипSteps    = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "steps");
				СписокШагов = Фабрика.Создать(ТипSteps);
				
				
				
				Если СтрСтроки.ЭтоScenarioOutline = Истина Тогда
					ОбойтиДеревоДляОтчетаxUnit(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
				Иначе
					Для каждого СтрРезультатПрохожденияТестовШагов Из РезультатПрохожденияТестовСценария.РезультатПрохожденияТестовШагов Цикл
						ТипStep   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "step");
						Шаг       = Фабрика.Создать(ТипStep);
						Шаг.name  = СтрРезультатПрохожденияТестовШагов.Имя;
						Шаг.title = СтрРезультатПрохожденияТестовШагов.Имя;
						
						Если СтрРезультатПрохожденияТестовШагов.ВремяНачала <> Неопределено Тогда
							Шаг.start = СтрРезультатПрохожденияТестовШагов.ВремяНачала;
							Шаг.stop  = СтрРезультатПрохожденияТестовШагов.ВремяОкончания;
						КонецЕсли; 
						
						ЗаписатьСтатусВШагИлиСценарий(Шаг,СтрРезультатПрохожденияТестовШагов.Статус);
						
						СписокШагов.step.Добавить(Шаг);
					КонецЦикла;
				КонецЕсли;	 
				
				ЗаписатьСтатусВШагИлиСценарий(Сценарий,СтрСтроки.Статус);
				Если (СтрСтроки.Статус = "Failed") или (СтрСтроки.Статус = "Pending") Тогда
					ТипFailure            = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "failure");
					ОбъектFailure         = Фабрика.Создать(ТипFailure);
					ОбъектFailure.message = РезультатПрохожденияТестовСценария.ОписаниеОшибки;
					
					Сценарий.failure = ОбъектFailure;
				КонецЕсли; 
				Сценарий.steps = СписокШагов;
				
				Типlabels   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "labels");
				СписокМеток = Фабрика.Создать(Типlabels);
				ДобавитьМетку(Фабрика,СписокМеток,"story",СтрСтроки.Имя);
				Сценарий.labels = СписокМеток;
				
				СписокСценариев.test_case.Добавить(Сценарий);
				//Сообщить(СтрСтроки.Имя);
			КонецЕсли; 
		ИначеЕсли СтрСтроки.Шаг = Истина Тогда
			Если СтрСтроки.Родитель.ЭтоScenarioOutline = Истина Тогда
				//его не неадо добавлять в отчет, т.к. этот сценарий явно не выполняется
				ОбойтиДеревоДляОтчетаxUnit(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
			Иначе	
				ТипStep   = Фабрика.Тип("urn:model.allure.qatools.yandex.ru", "step");
				Шаг       = Фабрика.Создать(ТипStep);
				Шаг.name  = СтрСтроки.Имя;
				Шаг.title = СтрСтроки.Имя;
				
				Если СтрСтроки.ВремяНачала <> Неопределено Тогда
					Шаг.start = СтрСтроки.ВремяНачала;
					Шаг.stop  = СтрСтроки.ВремяОкончания;
				КонецЕсли; 
				
				ЗаписатьСтатусВШагИлиСценарий(Шаг,СтрСтроки.Статус);
				СписокШагов.step.Добавить(Шаг);
			КонецЕсли; 
		Иначе	
			ОбойтиДеревоДляОтчетаxUnit(СтрСтроки,Фабрика,ТекущаяФича,СписокСценариев,СписокШагов);
		КонецЕсли; 
	КонецЦикла;
КонецПроцедуры

Процедура СформироватьОтчетxUnit(СтруктураОФ = Неопределено) Экспорт
	Перем СтарыйКаталог, ПутьКВременномуКаталогуНаСервере, ИмяФайла;
	СтарыйКаталог = КаталогOutputxUnit;
	
	ОтчетВРежимеУФ = Ложь;
	Если СтруктураОФ = Неопределено Тогда
		ОтчетВРежимеУФ = Ложь;
		ИмяФайла     = КаталогИнструментов + "/vendor/allure-framework/allure.xsd"; 
	Иначе	
		ОтчетВРежимеУФ = Истина;
		МассивXMLОтчетаxUnit = Новый Массив;
		СтруктураОФ.Вставить("МассивXMLОтчетаxUnit", МассивXMLОтчетаxUnit);
		
		ИмяФайла = ПолучитьИмяВременногоФайла("xsd");
	    СхемаAllure = СтруктураОФ.СхемаAllure;
		СхемаAllure.Записать(ИмяФайла);
		
		ПараметрыОтчетаУФ    = СтруктураОФ;
		ПутьКВременномуКаталогуНаСервере = КаталогВременныхФайлов() + Лев(Строка(Новый УникальныйИдентификатор), 8);
		СоздатьКаталог(ПутьКВременномуКаталогуНаСервере);
		КаталогOutputxUnit = ПутьКВременномуКаталогуНаСервере;
	КонецЕсли;

	Файл = Новый Файл(КаталогOutputxUnit);
	Если Не Файл.Существует() Тогда
		СделатьСообщение("Не могу сфомировать отчет xUnit. Не существует каталог для вывода отчета.");
		Возврат;
	КонецЕсли; 
	
	Фабрика      = СоздатьФабрикуXDTO(ИмяФайла);
	КаталогOutputxUnit = ДополнитьСлешВПуть(КаталогOutputxUnit);
	ОбойтиДеревоДляОтчетаxUnit(ДеревоТестов, Фабрика);
	КаталогOutputxUnit = СтарыйКаталог;
	
КонецПроцедуры

//}Отчет xUnit


//портирован блок ассертов из проекта xUnitFor1C (https://github.com/xDrivenDevelopment/xUnitFor1C)
//был взят релиз 3.0.0.3
//{ МЕТОДЫ ДЛЯ ПРОВЕРКИ ЗНАЧЕНИЙ (assertions). 
Функция ФорматДСО(ДопСообщениеОшибки)
	Если ДопСообщениеОшибки = "" Тогда
		Возврат "";
	КонецЕсли;
	
	Возврат Символы.ПС + ДопСообщениеОшибки;
КонецФункции

Процедура Проверить(_Истина, ДопСообщениеОшибки = "") Экспорт
	Если Не _Истина Тогда
		СообщениеОшибки = "Переданный параметр ("+Формат(_Истина, "БЛ=ложь; БИ=истина")+") не является Истиной, а хотели, чтобы являлся." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьИстину(_Истина, ДопСообщениеОшибки = "") Экспорт
	Проверить(_Истина, ДопСообщениеОшибки);
КонецПроцедуры

Процедура ПроверитьЛожь(_Ложь, ДопСообщениеОшибки = "") Экспорт
	Если _Ложь Тогда
		СообщениеОшибки = "Переданный параметр ("+Формат(_Ложь, "БЛ=ложь; БИ=истина")+") не является Ложью, а хотели, чтобы являлся." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьДату(_Дата, _Период, ДопСообщениеОшибки = "") Экспорт
	Если _Дата < _Период.ДатаНачала или _Дата > _Период.ДатаОкончания Тогда
		представление = ПредставлениеПериода(_Период.ДатаНачала, _Период.ДатаОкончания, "ФП = Истина");
		СообщениеОшибки = "Переданный параметр ("+Формат(_Дата, "ДФ='dd.MM.yyyy HH:mm:ss'")+") не входит в период "+представление+", а хотели, чтобы являлся." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьРавенствоДатСТочностью2Секунды(_Дата, _Дата2, ДопСообщениеОшибки = "") Экспорт
	Если _Дата < _Дата2-2 или _Дата > _Дата2+2 Тогда
		СообщениеОшибки = "Переданная дата ("+Формат(_Дата, "ДФ='dd.MM.yyyy HH:mm:ss'")+") не равна дате ("+Формат(_Дата2, "ДФ='dd.MM.yyyy HH:mm:ss'")+") с точностью до 2-х секунд, а хотели, чтобы они равнялись." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьРавенство(_1, _2, ДопСообщениеОшибки = "") Экспорт
	Если _1 <> _2 Тогда
		СообщениеОшибки = "Сравниваемые значения ("+_1+"; "+_2+") не равны, а хотели, чтобы были равны." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьНеРавенство(_1, _2, ДопСообщениеОшибки = "") Экспорт
	Если _1 = _2 Тогда
		СообщениеОшибки = "Сравниваемые значения ("+_1+"; "+_2+") равны, а хотели, чтобы были не равны." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьБольше(_Больше, _Меньше, ДопСообщениеОшибки = "") Экспорт
	Если _Больше <= _Меньше Тогда
		СообщениеОшибки = "Первый параметр ("+_Больше+") меньше или равен второму ("+_Меньше+") а хотели, чтобы был больше." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьБольшеИлиРавно(_Больше, _Меньше, ДопСообщениеОшибки = "") Экспорт
	Если _Больше < _Меньше Тогда
		СообщениеОшибки = "Первый параметр ("+_Больше+") меньше второго ("+_Меньше+") а хотели, чтобы был больше или равен." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьМеньше(проверяемоеЗначение1, проверяемоеЗначение2, СообщениеОбОшибке = "") Экспорт
	Если проверяемоеЗначение1 >= проверяемоеЗначение2 Тогда
		СообщениеОшибки = "Значение <"+проверяемоеЗначение1+"> больше или равно, чем <"+проверяемоеЗначение2+">, а ожидалось меньше"+
				ФорматДСО(СообщениеОбОшибке);
		ВызватьОшибкуПроверки(СообщениеОшибки)
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьМеньшеИлиРавно(проверяемоеЗначение1, проверяемоеЗначение2, СообщениеОбОшибке = "") Экспорт
	Если проверяемоеЗначение1 > проверяемоеЗначение2 Тогда
		СообщениеОшибки = "Значение <"+проверяемоеЗначение1+"> больше, чем <"+проверяемоеЗначение2+">, а ожидалось меньше или равно"+
				ФорматДСО(СообщениеОбОшибке);
		ВызватьОшибкуПроверки(СообщениеОшибки)
	КонецЕсли; 
КонецПроцедуры

Процедура ПроверитьВыполнилось(Знач СтрокаАлгоритм, ПараметрыИлиДопСообщениеОшибки = Неопределено, Знач ДопСообщениеОшибки = "") Экспорт
	Перем Параметры;
	
	Если ТипЗнч(ПараметрыИлиДопСообщениеОшибки) = Тип("Строка") Тогда
		ДопСообщениеОшибки = ПараметрыИлиДопСообщениеОшибки;
	Иначе
		Параметры = ПараметрыИлиДопСообщениеОшибки;
	КонецЕсли;
	Попытка
		Выполнить(СтрокаАлгоритм);
	Исключение
		ПолученноеОписаниеОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		СообщениеОшибки = "Хотели, чтобы алгоритм """+СтрокаАлгоритм+""" выполнился, а он упал с ошибкой """+ПолученноеОписаниеОшибки+"""." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецПопытки;
	
КонецПроцедуры

Процедура ПроверитьМетодВыполнился(Объект, Знач ИмяМетода, ПараметрыИлиДопСообщениеОшибки = Неопределено, Знач ДопСообщениеОшибки = "") Экспорт
	Перем Параметры;
	
	Если ТипЗнч(ПараметрыИлиДопСообщениеОшибки) = Тип("Строка") Тогда
		ДопСообщениеОшибки = ПараметрыИлиДопСообщениеОшибки;
	Иначе
		Параметры = ПараметрыИлиДопСообщениеОшибки;
		Если Параметры <> Неопределено Тогда
			ТипПараметра = ТипЗнч(Параметры);
			Если ТипПараметра <> Тип("Массив") Тогда
				ВызватьИсключение ("Ожидали, что вторым параметром будет передан массив параметров для метода <"+ИмяМетода+">, а получили другой объект с типом <"+ТипПараметра+">");
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыСтрока = ПараметрыСтрокой(Параметры);
	
	СтрокаВыполнения = "Объект." + ИмяМетода + "(" + ПараметрыСтрока + ")";
	
	Попытка
		Выполнить(СтрокаВыполнения);
	Исключение
		ПолученноеОписаниеОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		СообщениеОшибки = "Хотели, чтобы код """+СтрокаВыполнения+""" выполнился, а он упал с ошибкой """+ПолученноеОписаниеОшибки+"""." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецПопытки;
	
КонецПроцедуры

Функция ПараметрыСтрокой(Параметры, ИмяПеременной = "Параметры")
	
	ПараметрыСтрока = "";
	Если Параметры <> Неопределено Тогда
		Если ТипЗнч(Параметры) = Тип("Массив") Тогда
			Для Индекс = 0 По Параметры.ВГраница() Цикл 
				ПараметрыСтрока = ПараметрыСтрока + ", " + ИмяПеременной + "[" + Формат(Индекс, "ЧН=0; ЧГ=0") + "]";
			КонецЦикла;
			ПараметрыСтрока = Сред(ПараметрыСтрока, 3);
		Иначе
			ПараметрыСтрока = ИмяПеременной;
		КонецЕсли;
	КонецЕсли;
	
	Возврат ПараметрыСтрока;
	
КонецФункции

Процедура ПроверитьНеВыполнилось(Знач СтрокаАлгоритм, ПараметрыИлиОжидаемоеОписаниеОшибки, Знач ОжидаемоеОписаниеОшибкиИлиДопСообщениеОшибки = "", Знач ДопСообщениеОшибки = "") Экспорт
	Перем Параметры, ОжидаемоеОписаниеОшибки; 
	Если ТипЗнч(ПараметрыИлиОжидаемоеОписаниеОшибки) = Тип("Строка") Тогда
		ОжидаемоеОписаниеОшибки = ПараметрыИлиОжидаемоеОписаниеОшибки;
		ДопСообщениеОшибки = ОжидаемоеОписаниеОшибкиИлиДопСообщениеОшибки;
	Иначе
		Параметры = ПараметрыИлиОжидаемоеОписаниеОшибки;
		ОжидаемоеОписаниеОшибки = ОжидаемоеОписаниеОшибкиИлиДопСообщениеОшибки;
	КонецЕсли;
	Попытка
		Выполнить(СтрокаАлгоритм);
	Исключение
		ПолученноеОписаниеОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		Если Найти(ПолученноеОписаниеОшибки, ОжидаемоеОписаниеОшибки) = 0 Тогда
			ВызватьОшибкуПроверки("Хотели, чтобы алгоритм """+СтрокаАлгоритм+""" упал с сообщением об ошибке """+ОжидаемоеОписаниеОшибки+""", а он упал с сообщением """+ПолученноеОписаниеОшибки+"""." + ФорматДСО(ДопСообщениеОшибки));
		КонецЕсли;
		Возврат;
	КонецПопытки;
	
	ВызватьОшибкуПроверки("Хотели, чтобы алгоритм """+СтрокаАлгоритм+""" упал, а он выполнился" + ФорматДСО(ДопСообщениеОшибки));
	
КонецПроцедуры

Процедура ПроверитьМетодНеВыполнился(Объект, ИмяМетода, ПараметрыИлиОжидаемоеОписаниеОшибки, Знач ОжидаемоеОписаниеОшибкиИлиДопСообщениеОшибки = "", Знач ДопСообщениеОшибки = "") Экспорт
	Перем Параметры, ОжидаемоеОписаниеОшибки; 
	
	Если ТипЗнч(ПараметрыИлиОжидаемоеОписаниеОшибки) = Тип("Строка") Тогда
		ОжидаемоеОписаниеОшибки = ПараметрыИлиОжидаемоеОписаниеОшибки;
		ДопСообщениеОшибки = ОжидаемоеОписаниеОшибкиИлиДопСообщениеОшибки;
	Иначе
		Параметры = ПараметрыИлиОжидаемоеОписаниеОшибки;
		Если Параметры <> Неопределено Тогда
			ТипПараметра = ТипЗнч(Параметры);
			Если ТипПараметра <> Тип("Массив") Тогда
				ВызватьИсключение ("Ожидали, что третьим параметром будет передан массив параметров для метода <"+ИмяМетода+">, а получили другой объект с типом <"+ТипПараметра+">");
			КонецЕсли;
		КонецЕсли;
		ОжидаемоеОписаниеОшибки = ОжидаемоеОписаниеОшибкиИлиДопСообщениеОшибки;
	КонецЕсли;
	
	ПараметрыСтрока = ПараметрыСтрокой(Параметры);
	
	СтрокаВыполнения = "Объект." + ИмяМетода + "(" + ПараметрыСтрока + ")";
	
	Попытка
		Выполнить(СтрокаВыполнения);
	Исключение
		ПолученноеОписаниеОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		Если Найти(ПолученноеОписаниеОшибки, ОжидаемоеОписаниеОшибки) = 0 Тогда
			ВызватьОшибкуПроверки("Хотели, чтобы код """+СтрокаВыполнения+""" упал с сообщением об ошибке """+ОжидаемоеОписаниеОшибки+""", а он упал с сообщением """+ПолученноеОписаниеОшибки+"""." + ФорматДСО(ДопСообщениеОшибки));
		КонецЕсли;
		Возврат;
	КонецПопытки;
	
	ВызватьОшибкуПроверки("Хотели, чтобы код """+СтрокаВыполнения+""" упал, а он выполнился" + ФорматДСО(ДопСообщениеОшибки));
	
КонецПроцедуры

// проверка идет через ЗначениеЗаполнено, но мутабельные значение всегда считаем заполненными
Процедура ПроверитьЗаполненность(ПроверяемоеЗначение, ДопСообщениеОшибки = "") Экспорт
	Попытка
		фЗаполнено = ЗначениеЗаполнено(ПроверяемоеЗначение);
	Исключение
		Возврат;
	КонецПопытки;
	Если НЕ фЗаполнено Тогда
		ВызватьОшибкуПроверки("Значение ("+ПроверяемоеЗначение+") не заполнено, а ожидалась заполненность" + ФорматДСО(ДопСообщениеОшибки));
	КонецЕсли; 
КонецПроцедуры

Процедура ПроверитьНеЗаполненность(ПроверяемоеЗначение, ДопСообщениеОшибки = "") Экспорт
	СообщениеОшибки = "Значение ("+ПроверяемоеЗначение+") заполнено, а ожидалась незаполненность" + ФорматДСО(ДопСообщениеОшибки);
	Попытка
		фЗаполнено = ЗначениеЗаполнено(ПроверяемоеЗначение);
	Исключение
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецПопытки;
	Если фЗаполнено Тогда
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли; 
КонецПроцедуры

Процедура ПроверитьТип(значение, ТипИлиИмяТипа, ДопСообщениеОшибки = "") Экспорт
	Если ТипЗнч(ТипИлиИмяТипа) = Тип("Строка") Тогда
		искомыйТип = Тип(ТипИлиИмяТипа);
	ИначеЕсли ТипЗнч(ТипИлиИмяТипа) = Тип("Тип") Тогда
		искомыйТип = ТипИлиИмяТипа;
	Иначе
		ВызватьИсключение ("ПроверитьТип: Тип значения параметра ТипИлиИмяТипа должен быть <Тип> или <Строка>, а получили <"+ ТипЗнч(ТипИлиИмяТипа) + ">" + ФорматДСО(ДопСообщениеОшибки));
	КонецЕсли;
	Если ТипЗнч(значение) <> искомыйТип Тогда
		ВызватьОшибкуПроверки("Типом значения <"+значение+"> является <"+ТипЗнч(значение)+">, а ожидался тип <"+ТипИлиИмяТипа+">."+ФорматДСО(ДопСообщениеОшибки));
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьВхождение(строка, подстрокаПоиска, ДопСообщениеОшибки = "") Экспорт
	Если Найти(строка, подстрокаПоиска) = 0 Тогда
		ПредставлениеСтроки = "<"+строка+">";
		Если СтрДлина(строка) > 20 Тогда
			ПредставлениеСтроки = ПредставлениеСтроки + Символы.ПС;
		КонецЕсли;
		ПредставлениеПодСтроки = "<"+подстрокаПоиска+">";
		Если СтрДлина(подстрокаПоиска) > 20 Тогда
			ПредставлениеПодСтроки = ПредставлениеПодСтроки + Символы.ПС;
		КонецЕсли;
		СообщениеОшибки = "Искали в "+ПредставлениеСтроки+" подстроку "+ПредставлениеПодСтроки+", но не нашли." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

//Коллекция - Массив, Структура, Соответствие, ФиксированныйМассив, ФиксированнаяСтруктура, ФиксированноеСоответствие, СписокЗначений
Процедура ПроверитьВхождениеВКоллекцию(Элемент, Коллекция, ДопСообщениеОшибки = "") Экспорт
	Нашли = Неопределено;
	ТипКоллекции = ТипЗнч(Коллекция);
	Если ТипКоллекции = Тип("Массив") или ТипКоллекции = Тип("ФиксированныйМассив") Тогда
		Нашли = Коллекция.Найти(Элемент) <> Неопределено;
	ИначеЕсли ТипКоллекции = Тип("Структура") или ТипКоллекции = Тип("Соответствие") 
			или ТипКоллекции = Тип("ФиксированнаяСтруктура") или ТипКоллекции = Тип("ФиксированноеСоответствие") Тогда
		Для каждого КлючЗначение Из Коллекция Цикл
			Нашли = КлючЗначение.Значение = Элемент;
			Если Нашли Тогда
				Прервать;
			КонецЕсли;
		КонецЦикла;
	ИначеЕсли ТипКоллекции = Тип("СписокЗначений") Тогда
		Нашли = Коллекция.НайтиПоЗначению(Элемент) <> Неопределено;
	КонецЕсли;
	Если Нашли = Неопределено Тогда
		СообщениеОшибки = "Утверждение ""ПроверитьВхождениеВКоллекцию"" не умеет работать с типом коллекции <"+ТипКоллекции+">." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьИсключение СообщениеОшибки;
	КонецЕсли;
	Если Не Нашли Тогда
		СообщениеОшибки = "Не нашли элемент <"+Элемент+"> в коллекции, а хотели, чтобы он был в коллекции." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьВалидностьЗапросаСКД(ТекстЗапроса, ДопСообщениеОшибки = "") Экспорт
	
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных 					  = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить(); 
	ИсточникДанных.Имя                = "ИсточникДанных";
	ИсточникДанных.СтрокаСоединения   = "";
	ИсточникДанных.ТипИсточникаДанных = "Local";
	
	НаборДанных 							 = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
	НаборДанных.Имя            				 = "НаборДанных";
	НаборДанных.ИсточникДанных 				 = "ИсточникДанных";
	НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
	НаборДанных.Запрос 						 = ТекстЗапроса;
	
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	Попытка
		КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных));
	Исключение
		СообщениеОшибки = ОписаниеОшибки() + "." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецПопытки;
	
КонецПроцедуры // ПроверитьВалидностьЗапросаСКД()

Процедура ПроверитьНаличиеОбъектаИБ(ссылка, ДопСообщениеОшибки = "") Экспорт
	Если Не ЗначениеЗаполнено(ссылка) Тогда
		СообщениеОшибки = "Ожидали заполненность ссылки, а получили пустую ссылку." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
	лОбъект = ссылка.ПолучитьОбъект();
	Если лОбъект = Неопределено Тогда
		СообщениеОшибки = "Ожидали существование объекта в ИБ, а получили объект не найден <" + ссылка + "> ." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
КонецПроцедуры

// Проеряет равенство файлов
// Параметры:
//  ПутьФайла1, ПутьФайла2 - полные пути к фалйам
//  ПарамСравнениеФайлов - структура с ключами:
//                ИгнорироватьПустоеПространство
//                СпособСравнения
//                УчитыватьРазделителиСтрок
//                УчитыватьРегистр
//  ПоказатьРазличия - в случае ошибки появляется окно сравнеия (для отладки)
Процедура ПроверитьРавенствоФайлов(ПутьФайла1, ПутьФайла2, ДопСообщениеОшибки = "", ПарамСравнениеФайлов = Неопределено, ПоказатьРазличия = Ложь) Экспорт
#Если ТолстыйКлиентОбычноеПриложение или ТолстыйКлиентУправляемоеПриложение Тогда
	Если ПарамСравнениеФайлов = Неопределено Тогда
		ПарамСравнениеФайлов = Новый Структура;
	КонецЕсли;
	СравнениеФайлов = Новый СравнениеФайлов;
	СравнениеФайлов.ПервыйФайл = ПутьФайла1;
	СравнениеФайлов.ВторойФайл = ПутьФайла2;
	Если Не ПарамСравнениеФайлов.Свойство("СпособСравнения") Тогда
		Файл = Новый Файл(ПутьФайла1);
		ТипФайла = НРег(Файл.Расширение);
		ТекстовыеТипы = ".txt,.xml";
		Если ТипФайла = ".mxl" Тогда
			ПарамСравнениеФайлов.Вставить("СпособСравнения", СпособСравненияФайлов.ТабличныйДокумент);
		ИначеЕсли Найти(ТекстовыеТипы, ТипФайла) > 0 Тогда
			ПарамСравнениеФайлов.Вставить("СпособСравнения", СпособСравненияФайлов.ТекстовыйДокумент);
		КонецЕсли;
	КонецЕсли;
	ЗаполнитьЗначенияСвойств(СравнениеФайлов, ПарамСравнениеФайлов);
	ФайлыИдентичны = СравнениеФайлов.Сравнить();
	Если Не ФайлыИдентичны Тогда
		Если ПоказатьРазличия Тогда // для удобства отладки и расследования ошибок
			СравнениеФайлов.ПоказатьРазличия();
		КонецЕсли;
		СообщениеОшибки = "Ожидали идентичность файлов, а получили, что они различны." + ФорматДСО(ДопСообщениеОшибки);
		ВызватьОшибкуПроверки(СообщениеОшибки);
	КонецЕсли;
#Иначе 
	ВызватьИсключение "Утверждение ПроверитьРавенствоФайлов можно использовать только в толстом клиенте!";
#КонецЕсли
КонецПроцедуры

Функция СравнитьТаблицы(ТаблицаОжиданий, ТаблицаРезультатов, ТаблицаРазличий)
	
	Если ТаблицаОжиданий.Количество() <> ТаблицаРезультатов.Количество() Тогда
		Возврат РезультатыСравненияТаблиц.РазноеКоличествоСтрок;
	КонецЕсли;
	
	Если ТаблицаОжиданий.Количество() = 0 Тогда
		Возврат РезультатыСравненияТаблиц.ТаблицыСовпадают; //Пустые таблицы всегда одинаковы
	КонецЕсли;
	
	//Проверим структуру колонок
	
	//TODO При этом сравнении в структуре ТаблицаРезультатов может оказаться больше колонок, чем в ТаблицаОжиданий,
	// так что для абсолютного точного сравнения нужно добавить проверку совпадения количества колонок.
	ОжидаемыеКолонки = ТаблицаОжиданий.Колонки;
	КолонкиРезультата = ТаблицаРезультатов.Колонки;
	Для Каждого Колонка Из ОжидаемыеКолонки Цикл
		Если КолонкиРезультата.Найти(Колонка.Имя) = Неопределено Тогда
			Возврат РезультатыСравненияТаблиц.РазличаютсяКолонки;
		КонецЕсли;
	КонецЦикла;
	
	Возврат СравнитьЗначенияТаблиц(ТаблицаОжиданий, ТаблицаРезультатов, ТаблицаРазличий);
	
КонецФункции

// портирован из Functest
Функция СравнитьЗначенияТаблиц(ТаблицаОжиданий, ТаблицаРезультатов, Различия)
	
	Различия = Новый ТаблицаЗначений;
	Различия.Колонки.Очистить();
	Различия.Колонки.Добавить("Строка",Новый ОписаниеТипов("Число"));
	Различия.Колонки.Добавить("Колонка",Новый ОписаниеТипов("Строка"));
	Различия.Колонки.Добавить("Ожидание");
	Различия.Колонки.Добавить("Результат");
	
	РезультатСравнения = РезультатыСравненияТаблиц.ТаблицыСовпадают;
	
	Колонки = ТаблицаОжиданий.Колонки;
	ГраницаСтрок = ТаблицаОжиданий.Количество() - 1;
	Для Индекс = 0 По ГраницаСтрок Цикл
		
		ОжидаемаяСтрока = ТаблицаОжиданий[Индекс];
		СтрокаРезультата = ТаблицаРезультатов[Индекс];
		
		Для Каждого Колонка Из Колонки Цикл
			ИмяКолонки = Колонка.Имя;
			
			ОжидаемоеЗначение = ОжидаемаяСтрока[ИмяКолонки];
			ЗначениеРезультата = СтрокаРезультата[ИмяКолонки];
			Если ОжидаемоеЗначение = ЗначениеРезультата
			 Или (Не ЗначениеЗаполнено(ОжидаемоеЗначение) И Не ЗначениеЗаполнено(ЗначениеРезультата)) Тогда //Пустые значения разных типов 1С-м не считаются равными :(
				Продолжить;
			КонецЕсли;
			
			Различие = Различия.Добавить();
			Различие.Строка = Индекс + 1;
			Различие.Колонка = ИмяКолонки;
			Различие.Ожидание = ОжидаемоеЗначение;
			Различие.Результат = ЗначениеРезультата;
			РезультатСравнения = РезультатыСравненияТаблиц.НеСовпадаютЗначенияВЯчейкеТаблицы;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Возврат РезультатСравнения;
	
КонецФункции


Процедура ПроверитьРавенствоТаблиц(Таб1, Таб2, ДопСообщениеОшибки = "") Экспорт
	
	Если ТипЗнч(Таб1) <> Тип("ТаблицаЗначений") Тогда
		ВызватьИсключение "ПроверитьРавенствоТаблиц: Первый параметр-таблица таблицей не является";
	КонецЕсли;
	Если ТипЗнч(Таб1) <> Тип("ТаблицаЗначений") Тогда
		ВызватьИсключение "ПроверитьРавенствоТаблиц: Второй параметр-таблица таблицей не является";
	КонецЕсли;
	
	Различия = Новый ТаблицаЗначений;
	РезультатСравнения = СравнитьТаблицы(Таб1, Таб2, Различия);
	
	Если РезультатыСравненияТаблиц.ТаблицыСовпадают <> РезультатСравнения Тогда
		
		ИменаРезультатов = Новый Соответствие;
		Для Каждого КлючЗначение Из РезультатыСравненияТаблиц Цикл
			ИменаРезультатов.Вставить(КлючЗначение.Значение, КлючЗначение.Ключ);
		КонецЦикла; 
		СтрокаОшибок = "Различия в таблицах:" + Символы.ПС;
		СтрокаОшибок = СтрокаОшибок + "Ожидали статус <" + ИменаРезультатов[РезультатыСравненияТаблиц.ТаблицыСовпадают] + ">, а получили <" + ИменаРезультатов[РезультатСравнения] + ">" + Символы.ПС;
		Для Каждого Строка Из Различия Цикл
			СтрокаОшибок = СтрокаОшибок + "Значение [" + Строка.Колонка + ":" + Строка.Строка + "]. Ожидали <" + Строка.Ожидание + ">, а получили <" + Строка.Результат + ">" + Символы.ПС;
		КонецЦикла;
		
		ВызватьОшибкуПроверки("Таблицы должны совпадать, а они различны" + Символы.ПС + СтрокаОшибок + Символы.ПС + ДопСообщениеОшибки);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПроверитьРавенствоТабличныхДокументовТолькоПоЗначениям(ТабДок1, ТабДок2, УчитыватьТолькоВидимыеКолонкиИлиДопСообщениеОшибки = Ложь, УчитыватьТолькоВидимыеСтрокиИлиДопСообщениеОшибки = Ложь, Знач ДопСообщениеОшибки = "") Экспорт
	
	Если ТипЗнч(ТабДок1) <> Тип("ТабличныйДокумент") Тогда
		ВызватьИсключение "ПроверитьРавенствоТабличныхДокументовТолькоПоЗначениям: Первый параметр-таблица не является табличным документов";
	КонецЕсли;
	Если ТипЗнч(ТабДок2) <> Тип("ТабличныйДокумент") Тогда
		ВызватьИсключение "ПроверитьРавенствоТабличныхДокументовТолькоПоЗначениям: Второй параметр-таблица не является табличным документов";
	КонецЕсли;
	
	УчитыватьТолькоВидимыеКолонки = Ложь;
	Если ТипЗнч(УчитыватьТолькоВидимыеКолонкиИлиДопСообщениеОшибки) = Тип("Булево") Тогда
		УчитыватьТолькоВидимыеКолонки = УчитыватьТолькоВидимыеКолонкиИлиДопСообщениеОшибки;
	ИначеЕсли ТипЗнч(УчитыватьТолькоВидимыеКолонкиИлиДопСообщениеОшибки) = Тип("Строка") Тогда
		ДопСообщениеОшибки = УчитыватьТолькоВидимыеКолонкиИлиДопСообщениеОшибки;
	КонецЕсли;
	УчитыватьТолькоВидимыеСтроки = Ложь;
	Если ТипЗнч(УчитыватьТолькоВидимыеСтрокиИлиДопСообщениеОшибки) = Тип("Булево") Тогда
		УчитыватьТолькоВидимыеСтроки = УчитыватьТолькоВидимыеСтрокиИлиДопСообщениеОшибки;
	ИначеЕсли ТипЗнч(УчитыватьТолькоВидимыеСтрокиИлиДопСообщениеОшибки) = Тип("Строка") Тогда
		ДопСообщениеОшибки = УчитыватьТолькоВидимыеСтрокиИлиДопСообщениеОшибки;
	КонецЕсли;
	
	Таб1 = ПолучитьТаблицуЗначенийИзТабличногоДокумента(ТабДок1, УчитыватьТолькоВидимыеКолонки, УчитыватьТолькоВидимыеСтроки);
	Таб2 = ПолучитьТаблицуЗначенийИзТабличногоДокумента(ТабДок2, УчитыватьТолькоВидимыеКолонки, УчитыватьТолькоВидимыеСтроки);
	
	ПроверитьРавенствоТаблиц(Таб1, Таб2, ДопСообщениеОшибки);
	
КонецПроцедуры

Процедура ВызватьОшибкуПроверки(СообщениеОшибки)
	
	Префикс = "["+ СтатусыРезультатаТестирования.ОшибкаПроверки + "]";
	ВызватьИсключение Префикс + " " + СообщениеОшибки;
	
КонецПроцедуры

Процедура ПропуститьТест(Знач Сообщение = "") Экспорт
	
	Префикс = "[" + СтатусыРезультатаТестирования.ТестПропущен + "]";
	Если ПустаяСтрока(Сообщение) Тогда
		Сообщение = НСтр("ru = 'Тест пропущен'");
	КонецЕсли;
	ВызватьИсключение Префикс + " " + Сообщение;
	
КонецПроцедуры

// портирован из Functest
Функция ПолучитьТаблицуЗначенийИзТабличногоДокумента(ТабличныйДокумент, УчитыватьТолькоВидимыеКолонки = Ложь, УчитыватьТолькоВидимыеСтроки = Ложь)
	
	ТипТабличногоДокумента = ТипЗнч(ТабличныйДокумент);
	Если ТипТабличногоДокумента <> Тип("ТабличныйДокумент") И ТипТабличногоДокумента <> Тип("ПолеТабличногоДокумента") Тогда
		ВызватьИсключение "ПолучитьТаблицуЗначенийИзТабличногоДокумента: Требуется тип ТабличныйДокумент или ПолеТабличногоДокумента";
	КонецЕсли;
	
	НомерПоследнейКолонки = ТабличныйДокумент.ШиринаТаблицы;
	НомерПоследнейСтроки = ТабличныйДокумент.ВысотаТаблицы;
	
	НоваяТаблицаЗначений = Новый ТаблицаЗначений;
	Колонки = НоваяТаблицаЗначений.Колонки;
	ТипСтрока = Новый ОписаниеТипов("Строка");
	
	// TODO При определении видимости не учитывается наличие нескольких форматов строк, сейчас видимоcть колонки определяется по формату первой строки
	УчитываемыеКолонки = Новый Массив;
	Для НомерКолонки = 1 По НомерПоследнейКолонки Цикл
		ОбластьКолонки = ТабличныйДокумент.Область(0, НомерКолонки, 1, НомерКолонки);
		
		УчитыватьКолонку = Не УчитыватьТолькоВидимыеКолонки Или ОбластьКолонки.Видимость;
		Если УчитыватьКолонку Тогда
			УчитываемыеКолонки.Добавить(НомерКолонки);
			ШиринаКолонки = ОбластьКолонки.ШиринаКолонки;
			Если ШиринаКолонки <= 1 Тогда
				ШиринаКолонки = 1;
			КонецЕсли;
			ИмяКолонки = "К" + Формат(Колонки.Количество() + 1, "ЧН=; ЧГ=0");
			Колонки.Добавить(ИмяКолонки, ТипСтрока, ИмяКолонки, ШиринаКолонки);
		КонецЕсли;
	КонецЦикла;
	
	ГраницаКолонок = УчитываемыеКолонки.ВГраница();
	Для НомерСтроки = 1 По НомерПоследнейСтроки Цикл
		
		Если УчитыватьТолькоВидимыеСтроки И Не ТабличныйДокумент.Область(НомерСтроки,, НомерСтроки).Видимость Тогда
			Продолжить;
		КонецЕсли;
		
		НоваяСтрока = НоваяТаблицаЗначений.Добавить();
		
		Для Индекс = 0 По ГраницаКолонок Цикл
			НомерКолонки = УчитываемыеКолонки[Индекс];
			Область = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
			НоваяСтрока[Индекс] = Область.Текст;
		КонецЦикла;
	КонецЦикла;
	
	Возврат НоваяТаблицаЗначений;
	
КонецФункции

//} МЕТОДЫ ДЛЯ ПРОВЕРКИ ЗНАЧЕНИЙ (assertions). 


//портирован блок генерации данных из проекта xUnitFor1C (https://github.com/xDrivenDevelopment/xUnitFor1C)
//был взят релиз 3.0.0.3
// { Методы генерации тестовых данных

// Разбивает строку на несколько строк по разделителю. Разделитель может иметь любую длину.
// Общий модуль СтроковыеФункцииКлиентСервер.
//
// Параметры:
//  Строка                 - Строка - текст с разделителями;
//  Разделитель            - Строка - разделитель строк текста, минимум 1 символ;
//  ПропускатьПустыеСтроки - Булево - признак необходимости включения в результат пустых строк.
//    Если параметр не задан, то функция работает в режиме совместимости со своей предыдущей версией:
//     - для разделителя-пробела пустые строки не включаются в результат, для остальных разделителей пустые строки
//       включаются в результат.
//     - если параметр Строка не содержит значащих символов или не содержит ни одного символа (пустая строка), то в
//       случае разделителя-пробела результатом функции будет массив, содержащий одно значение "" (пустая строка), а
//       при других разделителях результатом функции будет пустой массив.
//
//
// Возвращаемое значение:
//  Массив - массив строк.
//
// Примеры:
//  РазложитьСтрокуВМассивПодстрок(",один,,два,", ",") - возвратит массив из 5 элементов, три из которых  - пустые строки;
//  РазложитьСтрокуВМассивПодстрок(",один,,два,", ",", Истина) - возвратит массив из двух элементов;
//  РазложитьСтрокуВМассивПодстрок(" один   два  ", " ") - возвратит массив из двух элементов;
//  РазложитьСтрокуВМассивПодстрок("") - возвратит пустой массив;
//  РазложитьСтрокуВМассивПодстрок("",,Ложь) - возвратит массив с одним элементом "" (пустой строкой);
//  РазложитьСтрокуВМассивПодстрок("", " ") - возвратит массив с одним элементом "" (пустой строкой);
//
//&НаКлиенте
Функция РазложитьСтрокуВМассивПодстрок(Знач Строка, Знач Разделитель = ",", Знач ПропускатьПустыеСтроки = Неопределено) Экспорт
	
	Результат = Новый Массив;
	
	// для обеспечения обратной совместимости
	Если ПропускатьПустыеСтроки = Неопределено Тогда
		ПропускатьПустыеСтроки = ?(Разделитель = " ", Истина, Ложь);
		Если ПустаяСтрока(Строка) Тогда 
			Если Разделитель = " " Тогда
				Результат.Добавить("");
			КонецЕсли;
			Возврат Результат;
		КонецЕсли;
	КонецЕсли;
	//
	
	Позиция = Найти(Строка, Разделитель);
	Пока Позиция > 0 Цикл
		Подстрока = Лев(Строка, Позиция - 1);
		Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
			Результат.Добавить(Подстрока);
		КонецЕсли;
		Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
		Позиция = Найти(Строка, Разделитель);
	КонецЦикла;
	
	Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Строка) Тогда
		Результат.Добавить(Строка);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции 


Функция СоздатьДанныеПоМакетам(ТестОбъект, ИменаМакетов) Экспорт
	МассивИменМакетов = РазложитьСтрокуВМассивПодстрок(ИменаМакетов);
	МассивМакетов = Новый Массив;
	Для каждого ИмяМакета Из МассивИменМакетов Цикл
		МассивМакетов.Добавить(ТестОбъект.ПолучитьМакет(ИмяМакета));
	КонецЦикла;
	Возврат СоздатьДанныеПоТабличномуДокументу(МассивМакетов);
КонецФункции

Функция СоздатьДанныеПоТабличномуДокументу(ТабличныйДокументИлиМассивТабличныхДокументов, РежимыЗагрузкиИлиИмяКолонкиЗамещения = Неопределено, ИмяКолонкиЗамещения = Неопределено) Экспорт
	Перем РежимыЗагрузки;
	
	Если ТипЗнч(РежимыЗагрузкиИлиИмяКолонкиЗамещения) = Тип("Строка") Тогда
		ИмяКолонкиЗамещения = РежимыЗагрузкиИлиИмяКолонкиЗамещения;
	Иначе
		РежимыЗагрузки = РежимыЗагрузкиИлиИмяКолонкиЗамещения;
		Если РежимыЗагрузки <> Неопределено Тогда
			ТипПараметра = ТипЗнч(РежимыЗагрузки);
			Если ТипПараметра <> Тип("Структура") Тогда
				ВызватьИсключение ("Ожидали, что вторым параметром будет передана структура параметров для метода <СоздатьДанныеПоТабличномуДокументу>, а получили другой объект с типом <"+ТипПараметра+">");
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	МассивТабличныхДокументов = Новый Массив();
	Если ТипЗнч(ТабличныйДокументИлиМассивТабличныхДокументов) = Тип("ТабличныйДокумент") Тогда
		МассивТабличныхДокументов.Добавить(ТабличныйДокументИлиМассивТабличныхДокументов);
	ИначеЕсли ТипЗнч(ТабличныйДокументИлиМассивТабличныхДокументов) = Тип("Массив") Тогда
		МассивТабличныхДокументов = ТабличныйДокументИлиМассивТабличныхДокументов;
	КонецЕсли;
	Возврат СоздатьДанныеИзМакетов(МассивТабличныхДокументов, РежимыЗагрузки, ИмяКолонкиЗамещения);
КонецФункции

// удаляет созданные элементы (Справочники, Документы, Пользователи ИБ), регистры сведений не чистит - есть тесты
Функция УдалитьСозданныеДанные(Данные) Экспорт
	// обратный порядок нужен для получения правильного количества удаленных элементов, т.к Владелец.Удалить удаляет и подчиненные элементы из подчиненных справочников
	массивВОбратномПорядке = Новый Массив;
	Для каждого ключЗначение Из Данные Цикл
		массивВОбратномПорядке.Вставить(0, КлючЗначение.Значение);
	КонецЦикла;
	
	количествоУдаленных = 0;
	Для каждого элем Из массивВОбратномПорядке Цикл
		типЭлемента = ТипЗнч(элем);
		Если Справочники.ТипВсеСсылки().СодержитТип(типЭлемента) Тогда
			объект = элем.ПолучитьОбъект();
			Если объект <> Неопределено Тогда
				Попытка
					объект.Удалить();
					количествоУдаленных = количествоУдаленных + 1;
				Исключение
					Сообщить(ОписаниеОшибки());
				КонецПопытки;
			КонецЕсли; 
		ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(типЭлемента) Тогда
			объект = элем.ПолучитьОбъект();
			Если объект <> Неопределено Тогда
				Попытка
					объект.Удалить();
					количествоУдаленных = количествоУдаленных + 1;
				Исключение
					Сообщить(ОписаниеОшибки());
				КонецПопытки;
			КонецЕсли; 
		ИначеЕсли типЭлемента = Тип("ПользовательИнформационнойБазы") Тогда
			Попытка
				элем.Удалить();
				количествоУдаленных = количествоУдаленных + 1;
			Исключение
				Сообщить(ОписаниеОшибки());
			КонецПопытки;
		КонецЕсли; 
	КонецЦикла;
	Возврат количествоУдаленных;
КонецФункции

Функция СоздатьДанныеИзМакетов(МассивТабличныхДокументов, РежимыЗагрузки, ИмяКолонкиЗамещения)
	ПротоДанные = Новый Структура;
	Для каждого ТабличныйДокумент Из МассивТабличныхДокументов Цикл
		ПрочитатьДанныеИзМакета(ПротоДанные,ТабличныйДокумент,ИмяКолонкиЗамещения);
	КонецЦикла;
	ЗаменитьРежимыЗагрузки(ПротоДанные, РежимыЗагрузки);
	Данные = СоздатьТестовыеДанныеПоПротоДанным(ПротоДанные);
	Возврат Данные;
КонецФункции

Функция ПрочитатьДанныеИзМакета(ПротоДанные,ТабличныйДокумент,ИмяКолонкиЗамещения)
	
	СтрокаМакета = 1;
	НомерКолонкиМакета = 0;
	КолонкиМакета = КолонкиМакетаДанных();
	Пока НомерКолонкиМакета<ТабличныйДокумент.ШиринаТаблицы Цикл
		НомерКолонкиМакета = НомерКолонкиМакета + 1;
		ИмяКолонки = ТабличныйДокумент.Область("R" + 1 + "C" + НомерКолонкиМакета).Текст;
		Если Не ПустаяСтрока(ИмяКолонки) Тогда
			КолонкиМакета.Вставить(ИмяКолонки,НомерКолонкиМакета);
		КонецЕсли;
	КонецЦикла;
	
	ПроверитьКолонки(КолонкиМакета,ИмяКолонкиЗамещения);

	ДействиеТекущейСтроки = Неопределено;
	Пока СтрокаМакета<ТабличныйДокумент.ВысотаТаблицы Цикл
		СтрокаМакета = СтрокаМакета + 1;
		НомерСтроки = Формат(СтрокаМакета, "ЧГ=");
		
		//Если новый объект
		ИмяПеременной = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.ИмяПеременной);
		Если Не ПустаяСтрока(ИмяПеременной) Тогда
			Если ПротоДанные.Свойство(ИмяПеременной) Тогда
				ВызватьИсключение "Ошибка при создании данных из макета! Неуникальное имя переменной: ["+ИмяПеременной+"]";
			КонецЕсли;
			
			Тип = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Тип);
			Вид = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Вид);
			Режим = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Режим);
			Значение = ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения);			
			
			ПротоОбъект = СоздатьСтруктуруОписанияОбъекта();
			ПротоОбъект.ИмяПеременной = ИмяПеременной;
			ПротоОбъект.Тип = Тип;
			ПротоОбъект.Вид = Вид;
			ПротоОбъект.ИмяПредопределенного = Значение;
			ПротоОбъект.ПоляОбъекта = СоздатьТаблицуОписанияПолей();
			Если Не ПустаяСтрока(Режим) Тогда
				Если ПротоОбъект.Режимы.Свойство(Режим) Тогда
					ПротоОбъект.Режимы[Режим] = Истина;
				КонецЕсли;
			КонецЕсли;
			
			ПротоДанные.Вставить(ИмяПеременной,ПротоОбъект);
			ДействиеТекущейСтроки = "ЧитаемПоляОбъекта";
			Продолжить;
		КонецЕсли;
		
		//Табличные части
		ИмяТабЧасти = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.ТЧ);
		Если Не ПустаяСтрока(ИмяТабЧасти) Тогда
			Если ВРег(ИмяТабЧасти)="XDDMODS" или ВРег(ИмяТабЧасти)="XDDDATAGEN" Тогда
				ДействиеТекущейСтроки = "ЧитаемРежимы";
				Продолжить;
			КонецЕсли;
			Если ВРег(ИмяТабЧасти)="ДОПОЛНИТЕЛЬНЫЕСВОЙСТВА" Тогда
				ДействиеТекущейСтроки = "ЧитаемДопСвойства";
				Продолжить;
			КонецЕсли;
			Если ВРег(ИмяТабЧасти)="ОБМЕНДАННЫМИ" Тогда
				ДействиеТекущейСтроки = "ЧитаемОбменДанными";
				Продолжить;
			КонецЕсли;
			
			ТабЧасть = Неопределено;
			Если Не ПротоОбъект.ТабличныеЧасти.Свойство(ИмяТабЧасти,ТабЧасть) Тогда
				//Новая ТабЧасть
				ОписаниеПолейТЧ = СоздатьТаблицуОписанияПолей();
				ТабЧасть = Новый Массив;
				ТабЧасть.Добавить(ОписаниеПолейТЧ);
				ПротоОбъект.ТабличныеЧасти.Вставить(ИмяТабЧасти,ТабЧасть);
				ДействиеТекущейСтроки = "ЧитаемТабЧасть";
				Продолжить;
			Иначе
				//Новая строка ТабЧасти
				ОписаниеПолейТЧ = СоздатьТаблицуОписанияПолей();
				ТабЧасть.Добавить(ОписаниеПолейТЧ);
				ДействиеТекущейСтроки = "ЧитаемТабЧасть";
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		//Поля объекта
		Если ДействиеТекущейСтроки = "ЧитаемПоляОбъекта" Тогда
			ИмяРеквизита = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент, НомерСтроки, КолонкиМакета.Реквизит);
			Если Не ПустаяСтрока(ИмяРеквизита) Тогда
				НовоеПолеОбъекта = ПротоОбъект.ПоляОбъекта.Добавить();
				НовоеПолеОбъекта.Имя = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Реквизит);
				НовоеПолеОбъекта.Значение = ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения);
				НовоеПолеОбъекта.Режим = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Режим);
				НовоеПолеОбъекта.ДополнительныйТип = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.ДополнительныйТипЗначения);
				
				Ключ = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Ключ);				
				Если ВРег(Ключ) = "КЛЮЧ" Тогда
					ПротоОбъект.Ключи.Вставить(НовоеПолеОбъекта.Имя, НовоеПолеОбъекта.Значение);
				КонецЕсли;
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		//Поля табличной части
		Если ДействиеТекущейСтроки = "ЧитаемТабЧасть" Тогда
			ИмяРеквизитаТЧ = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент, НомерСтроки, КолонкиМакета.Реквизит);
			Если Не ПустаяСтрока(ИмяРеквизитаТЧ) Тогда
				НовоеПолеТЧ = ОписаниеПолейТЧ.Добавить();
				НовоеПолеТЧ.Имя = ИмяРеквизитаТЧ;
				НовоеПолеТЧ.Значение = ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения);
				НовоеПолеТЧ.Режим = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Режим);
				НовоеПолеТЧ.ДополнительныйТип = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.ДополнительныйТипЗначения);
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		//Режимы объекта
		Если ДействиеТекущейСтроки = "ЧитаемРежимы" Тогда
			КодРежима = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Реквизит);
			Режим = ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения);
			Если ВРег(КодРежима)="РЕЖИМ" Тогда
				Если ПротоОбъект.Режимы.Свойство(Режим) Тогда
					ПротоОбъект.Режимы[Режим] = Истина;
				КонецЕсли;
			КонецЕсли;
			Продолжить;
		КонецЕсли;
		
		//Дополнительные свойства
		Если ДействиеТекущейСтроки = "ЧитаемДопСвойства" Тогда
			ИмяДопСвойства = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент, НомерСтроки, КолонкиМакета.Реквизит);
			Если Не ПустаяСтрока(ИмяДопСвойства) Тогда
				НовоеПолеДопСвойств = ПротоОбъект.ДопСвойства.Добавить();
				НовоеПолеДопСвойств.Имя = ИмяДопСвойства;
				НовоеПолеДопСвойств.Значение = ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения);
				НовоеПолеДопСвойств.Режим = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Режим);
				НовоеПолеДопСвойств.ДополнительныйТип = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.ДополнительныйТипЗначения);
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		Если ДействиеТекущейСтроки = "ЧитаемОбменДанными" Тогда
			ИмяОбменДанными = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент, НомерСтроки, КолонкиМакета.Реквизит);
			Если Не ПустаяСтрока(ИмяОбменДанными) Тогда
				НовоеПолеОбменаДанными = ПротоОбъект.ОбменДанными.Добавить();
				НовоеПолеОбменаДанными.Имя = ИмяОбменДанными;
				НовоеПолеОбменаДанными.Значение = ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения);
				НовоеПолеОбменаДанными.Режим = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Режим);
				НовоеПолеОбменаДанными.ДополнительныйТип = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.ДополнительныйТипЗначения);
				Продолжить;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецФункции

Функция ПроверитьКолонки(КолонкиМакета,ИмяКолонкиЗамещения)
	Для каждого Колонка Из КолонкиМакета Цикл
		Если Колонка.Значение = "0" Тогда
			Если Колонка.Ключ = "ДополнительныйТипЗначения" или Колонка.Ключ = "Ключ" Тогда
				//Это не обязательная колонка - может быть и не заполнена
			Иначе
				ВызватьИсключение "Неверно задан макет. Неверная колонка в первой строке. Не указана обязательная колонка с именем ["+Колонка.Ключ+"]";
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	Если ЗначениеЗаполнено(ИмяКолонкиЗамещения) Тогда
		Если не КолонкиМакета.Свойство(ИмяКолонкиЗамещения) Тогда
			ВызватьИсключение "Указанное Имя колонки замещения ["+ИмяКолонкиЗамещения+"] не существует в макете.";
		КонецЕсли;
	КонецЕсли;
КонецФункции

Функция ПрочитатьЗначениеДанныхСтроки(ТабличныйДокумент,НомерСтроки,КолонкиМакета,ИмяКолонкиЗамещения)
	Значение = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета.Значение);
	Если ЗначениеЗаполнено(ИмяКолонкиЗамещения) Тогда
		ПриоритетноеЗначение = ПрочитатьЗначениеЯчейкиМакета(ТабличныйДокумент,НомерСтроки,КолонкиМакета[ИмяКолонкиЗамещения]);
		Если ЗначениеЗаполнено(ПриоритетноеЗначение) Тогда
			Значение = ПриоритетноеЗначение;
		КонецЕсли;
	КонецЕсли;
	Возврат Значение;
КонецФункции

Функция ПрочитатьЗначениеЯчейкиМакета(Макет,НомерСтроки,НомерКолонки);
	ТекстЯчейки = Неопределено;
	Если НомерСтроки<> "0" И НомерКолонки <> "0" Тогда
		ТекстЯчейки = Макет.Область("R" + НомерСтроки + "C" + НомерКолонки).Текст;
	КонецЕсли;
	Возврат ТекстЯчейки;
КонецФункции

Функция СоздатьСтруктуруОписанияОбъекта()
	СтруктураОписанияОбъекта = Новый Структура();
	СтруктураОписанияОбъекта.Вставить("Объект",Неопределено);
	СтруктураОписанияОбъекта.Вставить("Тип",Неопределено);
	СтруктураОписанияОбъекта.Вставить("Вид",Неопределено);
	СтруктураОписанияОбъекта.Вставить("ИмяПредопределенного",Неопределено);
	СтруктураОписанияОбъекта.Вставить("ИмяПеременной",Неопределено);
	СтруктураОписанияОбъекта.Вставить("Режимы",СоздатьСтруктуруРежимовОбъекта());
	СтруктураОписанияОбъекта.Вставить("Ключи", новый Структура);
	СтруктураОписанияОбъекта.Вставить("ПоляОбъекта",СоздатьТаблицуОписанияПолей());
	СтруктураОписанияОбъекта.Вставить("ТабличныеЧасти",Новый Структура);
	СтруктураОписанияОбъекта.Вставить("ДопСвойства",СоздатьТаблицуОписанияПолей());
	СтруктураОписанияОбъекта.Вставить("ОбменДанными",СоздатьТаблицуОписанияПолей());
	Возврат СтруктураОписанияОбъекта;
КонецФункции

Функция СоздатьСтруктуруРежимовОбъекта()
	Режимы = Новый Структура;
	Режимы.Вставить("Предопределенный",Ложь);
	Режимы.Вставить("СоздатьПоГуид",Ложь);
	Режимы.Вставить("ТолькоСоздание",Ложь);
	Режимы.Вставить("Проведение",Ложь);
	Режимы.Вставить("ОбменДанными",Ложь);
	Режимы.Вставить("Объект",Ложь);
	Режимы.Вставить("Группа",Ложь);
	Режимы.Вставить("ЭтотУзел",Ложь);
	Возврат Режимы;
КонецФункции


Функция СоздатьТаблицуОписанияПолей()
	тзОписаниеПолей = Новый ТаблицаЗначений;
	тзОписаниеПолей.Колонки.Добавить("Имя");
	тзОписаниеПолей.Колонки.Добавить("Значение");
	тзОписаниеПолей.Колонки.Добавить("Режим");
	тзОписаниеПолей.Колонки.Добавить("ДополнительныйТип");
	Возврат тзОписаниеПолей;
КонецФункции

Функция МенеджерыМетаданных()
	Менеджеры = Новый Структура;
	Менеджеры.Вставить("ПланОбмена",ПланыОбмена);
	Менеджеры.Вставить("Справочник",Справочники);
	Менеджеры.Вставить("Документ",Документы);
	Менеджеры.Вставить("БизнесПроцесс",БизнесПроцессы);
	Менеджеры.Вставить("Задача",Задачи);
	Менеджеры.Вставить("РегистрСведений",РегистрыСведений);
	Менеджеры.Вставить("РегистрНакопления",РегистрыНакопления);
	Менеджеры.Вставить("РегистрыБухгалтерии",РегистрыБухгалтерии);
	Менеджеры.Вставить("ПланВидовХарактеристик",ПланыВидовХарактеристик);
	Менеджеры.Вставить("ПользовательИБ",ПользователиИнформационнойБазы);
	Возврат Новый ФиксированнаяСтруктура(Менеджеры);
КонецФункции

Процедура ЗаменитьРежимыЗагрузки(ПротоДанные, РежимыЗагрузки)
	Если ЗначениеЗаполнено(РежимыЗагрузки) Тогда
		Для каждого КлючЗначение Из ПротоДанные Цикл
			ПротоОбъект = КлючЗначение.Значение;
			ЗаполнитьЗначенияСвойств(ПротоОбъект.Режимы, РежимыЗагрузки);
		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

Функция СоздатьТестовыеДанныеПоПротоДанным(ПротоДанные)
	Данные = Новый Структура;
	МенеджерыМетаданных = МенеджерыМетаданных();
	Для каждого ПротоОбъект из ПротоДанные Цикл
		ОбъектСсылка = ПолучитьОбъект(ПротоДанные,ПротоОбъект.Значение);
		Данные.Вставить(ПротоОбъект.Значение.ИмяПеременной,ОбъектСсылка);
	КонецЦикла;
	Возврат Данные;
КонецФункции

Функция ПолучитьОбъект(ПротоДанные,ПротоОбъект)
	ОбъектСсылка = Неопределено;
	Если ПротоОбъект.Объект<>Неопределено Тогда
		Возврат ПротоОбъект.Объект;
	ИначеЕсли ПротоОбъект.Тип = "Справочник" Тогда
		ОбъектСсылка = СоздатьОбъект_Справочник(ПротоДанные,ПротоОбъект);
		
	ИначеЕсли ПротоОбъект.Тип = "Документ" Тогда
		ОбъектСсылка = СоздатьОбъект_Документ_или_БизнесПроцесс_или_Задача(Документы, ПротоДанные,ПротоОбъект);
		
	ИначеЕсли ПротоОбъект.Тип = "РегистрСведений" Тогда
		ОбъектСсылка = СоздатьОбъект_Регистр(РегистрыСведений, ПротоДанные,ПротоОбъект);
	ИначеЕсли ПротоОбъект.Тип = "РегистрНакопления" Тогда
		ОбъектСсылка = СоздатьОбъект_Регистр(РегистрыНакопления, ПротоДанные,ПротоОбъект);
	ИначеЕсли ПротоОбъект.Тип = "РегистрБухгалтерии" Тогда
		ОбъектСсылка = СоздатьОбъект_Регистр(РегистрыБухгалтерии, ПротоДанные,ПротоОбъект);
		
	ИначеЕсли ПротоОбъект.Тип = "ПользовательИБ" Тогда
		ОбъектСсылка = СоздатьОбъект_ПользовательИБ(ПротоДанные,ПротоОбъект);
		
	ИначеЕсли ПротоОбъект.Тип = "БизнесПроцесс" Тогда
		ОбъектСсылка = СоздатьОбъект_Документ_или_БизнесПроцесс_или_Задача(БизнесПроцессы, ПротоДанные,ПротоОбъект);
	ИначеЕсли ПротоОбъект.Тип = "Задача" Тогда
		ОбъектСсылка = СоздатьОбъект_Документ_или_БизнесПроцесс_или_Задача(Задачи, ПротоДанные,ПротоОбъект);
	ИначеЕсли ПротоОбъект.Тип = "ПланОбмена" Тогда
		ОбъектСсылка = СоздатьОбъект_УзелПланаОбмена(ПротоДанные,ПротоОбъект);
	КонецЕсли;
	ПротоОбъект.Объект = ОбъектСсылка;
	Возврат ОбъектСсылка;
КонецФункции

Функция СоздатьОбъект_УзелПланаОбмена(ПротоДанные, ПротоОбъект)
	ПланОбменаМенеджер = ПланыОбмена[ПротоОбъект.Вид];
	
	//Подготовим ПротоОбъект
	Объект = ПолучитьОбъектЕслиВПротоДанныеПереданаСсылка(ПланОбменаМенеджер, ПротоОбъект);
	Если Объект = Неопределено И ЗначениеЗаполнено(ПротоОбъект.Ключи) Тогда
		Объект = НайтиОбъектПоКлючам(ПротоОбъект, ПланОбменаМенеджер, ПротоОбъект.Ключи);
	КонецЕсли;

	Если ПротоОбъект.Режимы.ТолькоСоздание И Объект <> Неопределено Тогда
		Возврат ПротоОбъект.Объект;
	КонецЕсли;	
	
	//Создание узла плана обмена
	Если Объект = Неопределено Тогда
		Если ПротоОбъект.Режимы.ЭтотУзел Тогда
			Попытка
				Объект = ПланОбменаМенеджер.ЭтотУзел().ПолучитьОбъект();
			Исключение
				Ошибка = ОписаниеОшибки();
				ВызватьИсключение "ПланОбмена." + ПротоОбъект.Вид + " не удалось получить узел этой ИБ." + Символы.ПС + Ошибка;
			КонецПопытки;
		ИначеЕсли ПротоОбъект.Режимы.СоздатьПоГуид Тогда
			ВызватьИсключение "Устарело и больше не поддерживается: https://github.com/xDrivenDevelopment/xUnitFor1C/issues/332";
		Иначе
			Попытка
				Объект = ПланОбменаМенеджер.СоздатьУзел();
			Исключение
				Ошибка = ОписаниеОшибки();
				ВызватьИсключение "ПланОбмена." + ПротоОбъект.Вид + " не удалось создать новый узел." + Символы.ПС + Ошибка;
			КонецПопытки;
		КонецЕсли;
		
		Если Объект.ЭтоНовый() Тогда
			Если Не ЗначениеЗаполнено(ПротоОбъект.Объект) Тогда
				ПротоОбъект.Объект = ПланОбменаМенеджер.ПолучитьСсылку(Новый УникальныйИдентификатор);
			КонецЕсли;
			Объект.УстановитьСсылкуНового(ПротоОбъект.Объект);
		Иначе
			ПротоОбъект.Объект = Объект.Ссылка;
		КонецЕсли;
	КонецЕсли;
	
	//Заполняем реквизиты узла плана обмена
	НаборМдРеквизитов = НаборРеквизитовМетаданных(ПротоОбъект.Тип, Объект.Метаданные());
	Для каждого стрПоле Из ПротоОбъект.ПоляОбъекта Цикл
		Объект[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные, стрПоле, НаборМдРеквизитов);
	КонецЦикла;
	
	Для каждого ТабЧасть из ПротоОбъект.ТабличныеЧасти Цикл
		Для каждого СтрокаТабЧасти Из ТабЧасть.Значение Цикл
			СтрокаТабЧастиОбъекта = Объект[ТабЧасть.Ключ].Добавить();
			объектМетаданныеТабличнаяЧасть = Объект.Метаданные().ТабличныеЧасти[ТабЧасть.Ключ];
			НаборМдРеквизитовТЧ = объектМетаданныеТабличнаяЧасть.Реквизиты;
			Для каждого стрПоле Из СтрокаТабЧасти Цикл
				СтрокаТабЧастиОбъекта[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные, стрПоле, НаборМдРеквизитовТЧ);
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	//Служебные поля и значения
	Если Не ЗначениеЗаполнено(Объект.Код) тогда
		Объект.УстановитьНовыйКод();
	КонецЕсли;
	
	ЗаполнитьДополнительныеСвойства(Объект, ПротоДанные, ПротоОбъект);
	
	ПредставлениеМетаданного = "узел плана обмена";
	Результат = ЗаписатьОбъектПриНеобходимости(Объект, ПротоОбъект, ПредставлениеМетаданного, Истина);
	
	Возврат Результат;
КонецФункции

Функция СоздатьОбъект_Справочник(ПротоДанные,ПротоОбъект)
	СпрМенеджер = Справочники[ПротоОбъект.Вид];
	
	//Подготовим ПротоОбъект
	стрПолеЭтоГруппа = ПротоОбъект.ПоляОбъекта.Найти("ЭтоГруппа","Имя");
	Если стрПолеЭтоГруппа<>Неопределено Тогда
		ПротоОбъект.Режимы.Группа = Булево(стрПолеЭтоГруппа.Значение);
		ПротоОбъект.ПоляОбъекта.Удалить(стрПолеЭтоГруппа);
	КонецЕсли;

	
	Если ПротоОбъект.ИмяПеременной = "_99_ИностраннаяКомпания_ТолькоДляГоловныхКонтрагентов____" Тогда
		ва = 1;
	КонецЕсли;	 
	
	Объект = ПолучитьОбъектЕслиВПротоДанныеПереданаСсылка(СпрМенеджер, ПротоОбъект);
	Если Объект=Неопределено И ЗначениеЗаполнено(ПротоОбъект.Ключи) Тогда
		Объект = НайтиОбъектПоКлючам(ПротоОбъект, СпрМенеджер, ПротоОбъект.Ключи);
	КонецЕсли;

	Если ПротоОбъект.Режимы.ТолькоСоздание И Объект<>Неопределено Тогда
		Возврат ПротоОбъект.Объект;
	КонецЕсли;	
	
	//Создание объекта справочника
	Если Объект=Неопределено Тогда
		Если ПротоОбъект.Режимы.Предопределенный Тогда
			Попытка
				Объект = СпрМенеджер[ПротоОбъект.ИмяПредопределенного].ПолучитьОбъект();
			Исключение
				Ошибка = ОписаниеОшибки();
				ВызватьИсключение "Справочник."+ПротоОбъект.Вид+" не удалось найти предопределенный элемент/группу ["+ПротоОбъект.ИмяПредопределенного+"]."+Символы.ПС+Ошибка;
			КонецПопытки;
		ИначеЕсли ПротоОбъект.Режимы.СоздатьПоГуид Тогда
			ВызватьИсключение "Устарело и больше не поддерживается: https://github.com/xDrivenDevelopment/xUnitFor1C/issues/332";
		ИначеЕсли ПротоОбъект.Режимы.Группа Тогда
			Попытка
				Объект = СпрМенеджер.СоздатьГруппу();
			Исключение
				Ошибка = ОписаниеОшибки();
				ВызватьИсключение "Справочник."+ПротоОбъект.Вид+" не удалось создать новую группу."+Символы.ПС+Ошибка;
			КонецПопытки;
		Иначе
			Попытка
				Объект = СпрМенеджер.СоздатьЭлемент();
			Исключение
				Ошибка = ОписаниеОшибки();
				ВызватьИсключение "Справочник."+ПротоОбъект.Вид+" не удалось создать новый элемент."+Символы.ПС+Ошибка;
			КонецПопытки;
		КонецЕсли;
		
		Если Объект.ЭтоНовый() Тогда
			Если Не ЗначениеЗаполнено(ПротоОбъект.Объект) Тогда
				ПротоОбъект.Объект = СпрМенеджер.ПолучитьСсылку(Новый УникальныйИдентификатор);
			КонецЕсли;
			Объект.УстановитьСсылкуНового(ПротоОбъект.Объект);
		Иначе
			ПротоОбъект.Объект = Объект.Ссылка;
		КонецЕсли;
	КонецЕсли;
	
	//Заполняем реквизиты справочника
	НаборМдРеквизитов = НаборРеквизитовМетаданных(ПротоОбъект.Тип, Объект.Метаданные());
	Для каждого стрПоле Из ПротоОбъект.ПоляОбъекта Цикл
		Объект[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитов);
	КонецЦикла;
	
	Для каждого мдТабЧасть из Объект.Метаданные().ТабличныеЧасти Цикл
		ЭтоРежимГруппа = ПротоОбъект.Режимы.Группа;
		Если (ЭтоРежимГруппа И мдТабЧасть.Использование<>Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляЭлемента)
			Или (Не ЭтоРежимГруппа И мдТабЧасть.Использование<>Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппы) Тогда
			
				Объект[мдТабЧасть.Имя].Очистить();
		КонецЕсли;
		 
	КонецЦикла;
	Для каждого ТабЧасть из ПротоОбъект.ТабличныеЧасти Цикл
		Для каждого СтрокаТабЧасти Из ТабЧасть.Значение Цикл
			СтрокаТабЧастиОбъекта = Объект[ТабЧасть.Ключ].Добавить();
			объектМетаданныеТабличнаяЧасть = Объект.Метаданные().ТабличныеЧасти[ТабЧасть.Ключ];
			НаборМдРеквизитовТЧ = объектМетаданныеТабличнаяЧасть.Реквизиты;
			Для каждого стрПоле Из СтрокаТабЧасти Цикл
				СтрокаТабЧастиОбъекта[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитовТЧ);
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	//Служебные поля и значения
	Если Не ЗначениеЗаполнено(Объект.Код) тогда
		Объект.УстановитьНовыйКод();
	КонецЕсли;
	
	ЗаполнитьОбменДанными(Объект, ПротоДанные, ПротоОбъект);
	ЗаполнитьДополнительныеСвойства(Объект, ПротоДанные, ПротоОбъект);
	
	ПредставлениеМетаданного = "справочника";
	Результат = ЗаписатьОбъектПриНеобходимости(Объект, ПротоОбъект, ПредставлениеМетаданного, Истина);
	
	Возврат Результат;
КонецФункции

Функция НайтиОбъектПоКлючам(ПротоОбъект, МенеджерОбъекта, СтруктураРеквизитовКлючей)
	Рез = Неопределено;
	МдОбъект = МенеджерОбъекта.ПустаяСсылка().Метаданные();
	МдПолноеИмя = МдОбъект.ПолноеИмя();
	МдРеквизиты = МдОбъект.Реквизиты;
	МдСтандартныеРеквизиты = МдОбъект.СтандартныеРеквизиты;
	
	ТекстЗапроса = "Выбрать Первые 1 Т.Ссылка Из "+МдПолноеИмя+" КАК Т Где Истина ";
	Запрос = Новый Запрос;
	Для каждого КлючЗначение Из СтруктураРеквизитовКлючей Цикл
		ИмяРеквизита = КлючЗначение.Ключ;
		ЗначениеРеквизита = КлючЗначение.Значение;
		Если МдРеквизиты.Найти(ИмяРеквизита) = Неопределено и Не ЕстьСтандартныйРеквизит(МдСтандартныеРеквизиты, ИмяРеквизита) Тогда
			ВызватьИсключение "В метаданных "+МдПолноеИмя+" не найден реквизит-ключ <"+ИмяРеквизита+">. Ошибка в макете данных";
		КонецЕсли;
		ТекстЗапроса = ТекстЗапроса + " И "+ИмяРеквизита+" = &"+ИмяРеквизита;
		Запрос.УстановитьПараметр(ИмяРеквизита, ЗначениеРеквизита);		
	КонецЦикла;
	Запрос.Текст = ТекстЗапроса;
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		ПротоОбъект.Объект = Выборка.Ссылка;
		Рез = ПротоОбъект.Объект.ПолучитьОбъект();
	КонецЕсли;
	
	Возврат Рез;
КонецФункции

Функция ЕстьСтандартныйРеквизит(МдСтандартныеРеквизиты, ИмяРеквизита)
	Для каждого РеквизитМд Из МдСтандартныеРеквизиты Цикл
		Если РеквизитМд.Имя = ИмяРеквизита Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	Возврат Ложь;
КонецФункции

Функция СоздатьОбъект_Документ_или_БизнесПроцесс_или_Задача(МенеджерВсехВидов, ПротоДанные,ПротоОбъект)
	ЭтоДокумент = МенеджерВсехВидов = Документы;
	ЭтоБизнесПроцесс = МенеджерВсехВидов = БизнесПроцессы;
	ЭтоЗадача = МенеджерВсехВидов = Задачи;
	
	Если ЭтоДокумент Тогда
		ПредставлениеМенеджера = "Документы";
	ИначеЕсли ЭтоБизнесПроцесс Тогда
		ПредставлениеМенеджера = "БизнесПроцессы";
	ИначеЕсли ЭтоЗадача Тогда
		ПредставлениеМенеджера = "Задачи";
	Иначе
		ВызватьИсключение "Требуется документ, бизнес-процесс или задача. Неизвестный менеджер "+ПротоОбъект.Тип+"."+ПротоОбъект.Вид+" . Переменная "+ПротоОбъект.ИмяПеременной;
	КонецЕсли;
	
	МенеджерОбъекта = МенеджерВсехВидов[ПротоОбъект.Вид];
	Объект = ПолучитьОбъектЕслиВПротоДанныеПереданаСсылка(МенеджерОбъекта, ПротоОбъект);
	Если Объект=Неопределено И ЗначениеЗаполнено(ПротоОбъект.Ключи) Тогда
		Объект = НайтиОбъектПоКлючам(ПротоОбъект, МенеджерОбъекта, ПротоОбъект.Ключи);
	КонецЕсли;
	
	Если ПротоОбъект.Режимы.ТолькоСоздание И Объект<>Неопределено Тогда
		Возврат ПротоОбъект.Объект;
	КонецЕсли;
	
	//Создание объекта
	Если Объект = Неопределено Тогда
		Попытка
			Если ЭтоДокумент Тогда
				Объект = МенеджерОбъекта.СоздатьДокумент();
			ИначеЕсли ЭтоБизнесПроцесс Тогда
				Объект = МенеджерОбъекта.СоздатьБизнесПроцесс();
			ИначеЕсли ЭтоЗадача Тогда
				Объект = МенеджерОбъекта.СоздатьЗадачу();
			КонецЕсли;
		Исключение
			Ошибка = ОписаниеОшибки();
			ВызватьИсключение ПредставлениеМенеджера+"."+ПротоОбъект.Вид+" не удалось создать новый элемент."+Символы.ПС+Ошибка;
		КонецПопытки;
	
		//Установка ссылки
		Если Объект.ЭтоНовый() Тогда
			Если Не ЗначениеЗаполнено(ПротоОбъект.Объект) Тогда
				ПротоОбъект.Объект = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор);
			КонецЕсли;
			Объект.УстановитьСсылкуНового(ПротоОбъект.Объект);
		КонецЕсли;
	КонецЕсли;
	
	//Заполняем реквизиты
	НаборМдРеквизитов = НаборРеквизитовМетаданных(ПротоОбъект.Тип, Объект.Метаданные());
	Для каждого стрПоле Из ПротоОбъект.ПоляОбъекта Цикл
		Объект[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитов);
	КонецЦикла;
	
	Для каждого мдТабЧасть из Объект.Метаданные().ТабличныеЧасти Цикл
		Объект[мдТабЧасть.Имя].Очистить();
	КонецЦикла;
	Для каждого ТабЧасть из ПротоОбъект.ТабличныеЧасти Цикл
		Для каждого СтрокаТабЧасти Из ТабЧасть.Значение Цикл
			СтрокаТабЧастиОбъекта = Объект[ТабЧасть.Ключ].Добавить();
			объектМетаданныеТабличнаяЧасть = Объект.Метаданные().ТабличныеЧасти[ТабЧасть.Ключ];
			НаборМдРеквизитовТЧ = объектМетаданныеТабличнаяЧасть.Реквизиты;
			Для каждого стрПоле Из СтрокаТабЧасти Цикл
				СтрокаТабЧастиОбъекта[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитовТЧ);
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	//Служебные поля и значения
	Если Не ЗначениеЗаполнено(Объект.Дата) Тогда
		Объект.Дата = ТекущаяДата();
	КонецЕсли;			
	Если Не ЗначениеЗаполнено(Объект.Номер) тогда
		Объект.УстановитьНовыйНомер();
	КонецЕсли;
	
	ЗаполнитьОбменДанными(Объект, ПротоДанные, ПротоОбъект);
	ЗаполнитьДополнительныеСвойства(Объект, ПротоДанные, ПротоОбъект);
	
	РежимЗаписи = Неопределено;
	Если ЭтоДокумент И Не ПротоОбъект.Режимы.Объект Тогда
		РежимЗаписи = РежимЗаписиДокумента.Запись;
		Если ПротоОбъект.Режимы.Проведение Тогда
			РежимЗаписи = РежимЗаписиДокумента.Проведение;
		КонецЕсли;
	КонецЕсли;
	Результат = ЗаписатьОбъектПриНеобходимости(Объект, ПротоОбъект, ПредставлениеМенеджера, Истина, РежимЗаписи);
	
	Возврат Результат;
КонецФункции

Функция СоздатьОбъект_Регистр(МенеджерРегистра, ПротоДанные,ПротоОбъект)
	ЭтоРегистрСведения = МенеджерРегистра = РегистрыСведений;
	ЭтоРегистрБухгалтерии = МенеджерРегистра = РегистрыБухгалтерии;
	ЭтоРегистрНакопления = МенеджерРегистра = РегистрыНакопления;
	
	Если ЭтоРегистрСведения Тогда
		ПредставлениеМдМенеджераРегистра = "РегистрыСведения";
	ИначеЕсли ЭтоРегистрБухгалтерии Тогда
		ПредставлениеМдМенеджераРегистра = "РегистрыБухгалтерии";
	ИначеЕсли ЭтоРегистрНакопления Тогда
		ПредставлениеМдМенеджераРегистра = "РегистрыНакопления";
	Иначе
		ВызватьИсключение "Неизвестный менеджер регистра "+ПротоОбъект.Тип+"."+ПротоОбъект.Вид+" . Переменная "+ПротоОбъект.ИмяПеременной;
	КонецЕсли;
	Если ЗначениеЗаполнено(ПротоОбъект.Ключи) Тогда
		ВызватьИсключение "Работа с ключами для "+ПредставлениеМдМенеджераРегистра+" пока не поддерживается";
	КонецЕсли;
	
	//Создание объекта
	ПротоНаборЗаписей = Неопределено;
	Если ПротоОбъект.ТабличныеЧасти.Свойство("Запись",ПротоНаборЗаписей) Тогда
		Попытка
			Объект = МенеджерРегистра[ПротоОбъект.Вид].СоздатьНаборЗаписей();
		Исключение
			Ошибка = ОписаниеОшибки();
			ВызватьИсключение ПредставлениеМдМенеджераРегистра+"."+ПротоОбъект.Вид+" не удалось создать новый НаборЗаписей."+Символы.ПС+Ошибка;
		КонецПопытки;
		
		МетаданныеНабора = Объект.Метаданные();
		НаборМдРеквизитов = НаборРеквизитовМетаданных(ПротоОбъект.Тип, МетаданныеНабора);
				
		РегистрСведенийПодчиненРегистратору = Истина;
		Если ЭтоРегистрСведения Тогда
			РегистрСведенийПодчиненРегистратору = МетаданныеНабора.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору;
			
		ИначеЕсли ЭтоРегистрБухгалтерии Тогда
			НаборВидовСубконто = Новый Структура;

			ПостфиксыСчетов = Новый Массив;
			Если МетаданныеНабора.Корреспонденция Тогда
				ПостфиксыСчетов.Добавить("Дт");
				ПостфиксыСчетов.Добавить("Кт");
			Иначе
				ПостфиксыСчетов.Добавить("");
			КонецЕсли;
			Для каждого ПостфиксСчета Из ПостфиксыСчетов Цикл
				НаборМдРеквизитов.Вставить("Счет"+ПостфиксСчета, МетаданныеНабора.ПланСчетов);
				Для НомерВидаСубконто = 1 По МетаданныеНабора.ПланСчетов.МаксКоличествоСубконто Цикл
					ОписаниеСубконто = Новый Структура("ИмяРеквизитаСчет,ИмяРеквизитаСубконто,НомерВидаСубконто", "Счет"+ПостфиксСчета, "Субконто"+ПостфиксСчета, НомерВидаСубконто-1);
					НаборВидовСубконто.Вставить("Субконто"+ПостфиксСчета+НомерВидаСубконто, ОписаниеСубконто);
				КонецЦикла;
			КонецЦикла;
		КонецЕсли;
		
		Для каждого СтрокаЗаписи Из ПротоНаборЗаписей Цикл
			ЗаписьНабора = Объект.Добавить();
			Для каждого стрПоле Из СтрокаЗаписи Цикл
				ЗначениеПоля = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитов);

				ОписаниеСубконто = Неопределено;
				Если ЭтоРегистрБухгалтерии И НаборВидовСубконто.Свойство(стрПоле.Имя, ОписаниеСубконто) Тогда
					ВидСубконто = ЗаписьНабора[ОписаниеСубконто.ИмяРеквизитаСчет].ВидыСубконто[ОписаниеСубконто.НомерВидаСубконто].ВидСубконто;
					ЗаписьНабора[ОписаниеСубконто.ИмяРеквизитаСубконто].Вставить(ВидСубконто, ЗначениеПоля);
				Иначе
					ЗаписьНабора[стрПоле.Имя] = ЗначениеПоля;
				КонецЕсли;
			КонецЦикла;
			
			Если РегистрСведенийПодчиненРегистратору Тогда
				ПроверитьЗаполненность(ЗаписьНабора.Регистратор, "Не задан регистратор для записей регистра "+ПредставлениеМдМенеджераРегистра+". Переменная "+ПротоОбъект.ИмяПеременной);
				Если НЕ ЗначениеЗаполнено(ЗаписьНабора.Период) Тогда
					ЗаписьНабора.Период = ЗаписьНабора.Регистратор.Дата;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
		ЗаписьНабора = Объект[0];
		Если РегистрСведенийПодчиненРегистратору Тогда
			Объект.Отбор.Регистратор.Установить(ЗаписьНабора.Регистратор);
		Иначе
			Для каждого МетаИзмерение Из МетаданныеНабора.Измерения Цикл
				ИмяИзмерения = МетаИзмерение.Имя;
				Если Объект.Отбор.Найти(ИмяИзмерения)	<> Неопределено Тогда
					Объект.Отбор[ИмяИзмерения].Установить(ЗаписьНабора[ИмяИзмерения]);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
		ЗаполнитьОбменДанными(Объект, ПротоДанные, ПротоОбъект);
		ЗаполнитьДополнительныеСвойства(Объект, ПротоДанные, ПротоОбъект);
		
	ИначеЕсли ЭтоРегистрСведения Тогда
		Попытка
			Объект = РегистрыСведений[ПротоОбъект.Вид].СоздатьМенеджерЗаписи();
		Исключение
			Ошибка = ОписаниеОшибки();
			ВызватьИсключение ПредставлениеМдМенеджераРегистра+"."+ПротоОбъект.Вид+" не удалось создать новый набор записей"+Символы.ПС+Ошибка;
		КонецПопытки;
		
		НаборМдРеквизитов = НаборРеквизитовМетаданных(ПротоОбъект.Тип, РегистрыСведений[ПротоОбъект.Вид].СоздатьНаборЗаписей().Метаданные());
		Для каждого стрПоле Из ПротоОбъект.ПоляОбъекта Цикл
			Объект[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитов);
		КонецЦикла;
	Иначе
		ВызватьИсключение ПредставлениеМдМенеджераРегистра+"."+ПротоОбъект.Вид+" в макете нет записей для регистра "+ПредставлениеМдМенеджераРегистра;
	КонецЕсли;
		
	ПредставлениеМетаданного = "набора записей "+ПредставлениеМдМенеджераРегистра;
	ЗаписатьОбъектПриНеобходимости(Объект, ПротоОбъект, ПредставлениеМетаданного, Ложь);
	
	Возврат Объект;
КонецФункции

Функция СоздатьОбъект_ПользовательИБ(ПротоДанные,ПротоОбъект)
	Если ЗначениеЗаполнено(ПротоОбъект.Ключи) Тогда
		ВызватьИсключение "Работа с ключами при создании пользователя ИБ пока не поддерживается";
	КонецЕсли;
	Объект = ПользователиИнформационнойБазы.СоздатьПользователя();
	
	параметрыПользователя = Новый Структура;
	параметрыПользователя.Вставить("Имя", "");
	параметрыПользователя.Вставить("ПолноеИмя", "");
	параметрыПользователя.Вставить("АутентификацияСтандартная", Истина);
	параметрыПользователя.Вставить("АутентификацияОС", Ложь);
	параметрыПользователя.Вставить("ПользовательОС", "");
	параметрыПользователя.Вставить("ОсновнойИнтерфейс", ""); //Метаданные.Интерфейсы.Администратор);
	параметрыПользователя.Вставить("Пароль", "пароль");
	параметрыПользователя.Вставить("ПоказыватьВСпискеВыбора", Истина);
	параметрыПользователя.Вставить("РежимЗапуска", РежимЗапускаКлиентскогоПриложения.Авто);
	параметрыПользователя.Вставить("Язык", Метаданные.Языки.Русский);
	массивРолей = Новый Массив;
	параметрыПользователя.Вставить("Роли", массивРолей);
	
	//Заполняем реквизиты справочника
	Для каждого стрПоле Из ПротоОбъект.ПоляОбъекта Цикл
		параметрыПользователя[стрПоле.Имя] = ПолучитьЗначениеПоля(ПротоДанные,стрПоле,Неопределено);
	КонецЦикла;
	ЗаполнитьЗначенияСвойств(Объект, параметрыПользователя,, "ОсновнойИнтерфейс,РежимЗапуска");
	
	ПротоНаборРолей = Неопределено;
	Если ПротоОбъект.ТабличныеЧасти.Свойство("Роли",ПротоНаборРолей) Тогда
		Для каждого СтрокаРоли Из ПротоНаборРолей Цикл
			Для каждого стрПоле Из СтрокаРоли Цикл
				Роль = Метаданные.Роли.Найти(ПолучитьЗначениеПоля(ПротоДанные,стрПоле,Неопределено));
				параметрыПользователя.Роли.Добавить(Роль);
			КонецЦикла;
		КонецЦикла;
	КонецЕсли;
	
	НашлиРежимЗапуска = Ложь;
	Для каждого ЗначениеРежимаЗапуска Из РежимЗапускаКлиентскогоПриложения Цикл
		Если НРег(""+ЗначениеРежимаЗапуска) = НРег(параметрыПользователя.РежимЗапуска) Тогда
			НашлиРежимЗапуска = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	Если НашлиРежимЗапуска Тогда
		Объект.РежимЗапуска = ЗначениеРежимаЗапуска;
	Иначе
		ВызватьИсключение "Не нашли режим запуска <"+параметрыПользователя.РежимЗапуска+">. Возможно, нужно указать с пробелом, например, ""Управляемое приложение""";
	КонецЕсли;
	
	Если ЗначениеЗаполнено(параметрыПользователя.ОсновнойИнтерфейс) Тогда
		Объект.ОсновнойИнтерфейс = Метаданные.Интерфейсы.Найти(параметрыПользователя.ОсновнойИнтерфейс);
	КонецЕсли;
	Для каждого роль Из параметрыПользователя.Роли Цикл
		Объект.Роли.Добавить(роль);
	КонецЦикла;
	
	ПредставлениеМетаданного = "пользователя ИБ ";
	ЗаписатьОбъектПриНеобходимости(Объект, ПротоОбъект, ПредставлениеМетаданного, Ложь);
	
	Возврат Объект.Имя;
КонецФункции

Функция ПолучитьОбъектЕслиВПротоДанныеПереданаСсылка(МенеджерОбъекта, ПротоОбъект)
	Перем Объект;
	стрПолеСсылка = ПротоОбъект.ПоляОбъекта.Найти("Ссылка","Имя");
	Если стрПолеСсылка<>Неопределено Тогда
		ПротоОбъект.Объект = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(стрПолеСсылка.Значение));
		ПротоОбъект.ПоляОбъекта.Удалить(стрПолеСсылка);
		Объект = ПротоОбъект.Объект.ПолучитьОбъект();
	КонецЕсли;
	Возврат Объект;
КонецФункции

Процедура ЗаполнитьОбменДанными(Объект, ПротоДанные, ПротоОбъект)
	Объект.ОбменДанными.Загрузка = ПротоОбъект.Режимы.ОбменДанными;
	
	//Дополнительные Свойства
	Для каждого стрДопСвойство Из ПротоОбъект.ДопСвойства Цикл
		Значение = ПолучитьЗначениеПоля(ПротоДанные,стрДопСвойство,Неопределено);
		Объект.ДополнительныеСвойства.Вставить(стрДопСвойство.Имя,Значение);
	КонецЦикла;
	Для каждого стрДопСвойство Из ПротоОбъект.ОбменДанными Цикл
		Значение = ПолучитьЗначениеПоля(ПротоДанные,стрДопСвойство,Неопределено);
		Объект.ОбменДанными[стрДопСвойство.Имя] = Значение;
	КонецЦикла;
КонецПроцедуры

Функция ЗаписатьОбъектПриНеобходимости(Объект, ПротоОбъект, ПредставлениеМетаданного, ЭтоСсылочныйОбъект, РежимЗаписи = Неопределено)
	Перем Результат;
	Если Не ПротоОбъект.Режимы.Объект Тогда
		Попытка
			Если РежимЗаписи = Неопределено Тогда
				Объект.Записать();
			Иначе
				Объект.Записать(РежимЗаписи);
			КонецЕсли;
			Если ЭтоСсылочныйОбъект Тогда
				Результат = Объект.Ссылка;
			КонецЕсли;
		Исключение
			Ошибка = ОписаниеОшибки();
			Ошибка = "Ошибка записи "+ПредставлениеМетаданного+" "+ПротоОбъект.Вид+", переменная "+ПротоОбъект.ИмяПеременной + Символы.ПС + Ошибка;
			ВызватьИсключение Ошибка;
		КонецПопытки;
	ИначеЕсли ЭтоСсылочныйОбъект Тогда
		Результат = Объект;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Процедура ЗаполнитьДополнительныеСвойства(Объект, ПротоДанные, ПротоОбъект)
	Для каждого стрДопСвойство Из ПротоОбъект.ДопСвойства Цикл
		Значение = ПолучитьЗначениеПоля(ПротоДанные,стрДопСвойство,Неопределено);
		Объект.ДополнительныеСвойства.Вставить(стрДопСвойство.Имя,Значение);
	КонецЦикла;
КонецПроцедуры

Функция ПолучитьЗначениеПоля(ПротоДанные,стрПоле,НаборМдРеквизитов)
	Значение = Неопределено;
	Если ПустаяСтрока(стрПоле.Режим) Тогда
		Если ЗначениеЗаполнено(стрПоле.ДополнительныйТип) Тогда
			ТипЗначения = Новый ОписаниеТипов(стрПоле.ДополнительныйТип);
			Значение = ТипЗначения.ПривестиЗначение(стрПоле.Значение);
		Иначе
			Значение = стрПоле.Значение;
		КонецЕсли;
	ИначеЕсли ВРег(стрПоле.Режим) = "ПЕРЕМ" Тогда
		Значение = ПротоДанные[стрПоле.Значение].Объект;
		Если Не ЗначениеЗаполнено(Значение) Тогда
			Значение = ПолучитьОбъект(ПротоДанные, ПротоДанные[стрПоле.Значение]);
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(Значение) Тогда
			ВызватьИсключение "ЗначениеНеНайдено: Реквизит <"+стрПоле.Имя+">: Искали значение <"+стрПоле.Значение+">, но не нашли!";
		КонецЕсли;
	ИначеЕсли ВРег(стрПоле.Режим) = "ТЕКУЩАЯДАТА" Тогда
		Значение = ТекущаяДата();
	ИначеЕсли ВРег(стрПоле.Режим) = "ВЫРАЖЕНИЕ" Тогда 
		Значение = Вычислить(стрПоле.Значение);
	Иначе
		Значение = ВычислитьЗначениеПоТипуПоля(НаборМдРеквизитов,стрПоле);
	КонецЕсли;
	Возврат Значение;
КонецФункции

Функция ВычислитьЗначениеПоТипуПоля(НаборМдРеквизитов,стрПоле)
	Значение = Неопределено;
	Режим = ВРег(стрПоле.Режим);
	//Если стрПоле.Имя = "ВидРасчета" Тогда
	//	вава = 1;
	//КонецЕсли;	 
	
	Попытка
		Если НаборМдРеквизитов = Неопределено Тогда
			Если НЕ ЗначениеЗаполнено(стрПоле.ДополнительныйТип) Тогда
				ВызватьИсключение "Не указан дополнительный тип значения";
			КонецЕсли;
			МетаданныеРеквизита = Неопределено;
		Иначе
			МетаданныеРеквизита = НаборМдРеквизитов[стрПоле.Имя];
		КонецЕсли; 
		УжеВычислилиЗначение = Ложь;
		ЕстьМетаданныеРеквизита = Ложь;
		Если Режим = "ГУИД" И МетаданныеРеквизита <> Неопределено И МетаданныеРеквизита.Тип.СодержитТип(Тип("УникальныйИдентификатор")) Тогда
			Значение = Новый УникальныйИдентификатор(стрПоле.Значение);
			УжеВычислилиЗначение = Истина;
		Иначе
			
			Если ЗначениеЗаполнено(стрПоле.ДополнительныйТип) Тогда
				ТипЗначения = Новый ОписаниеТипов(стрПоле.ДополнительныйТип);
			Иначе
				Если Метаданные.ПланыСчетов.Найти(МетаданныеРеквизита) <> Неопределено Тогда
					ТипЗначения = Новый ОписаниеТипов("ПланСчетовСсылка."+МетаданныеРеквизита.Имя);
				Иначе
					ТипЗначения = МетаданныеРеквизита.Тип;
				КонецЕсли;
			КонецЕсли;
			ЗначениеПоУмолчанию = ТипЗначения.ПривестиЗначение();
			Попытка
				МетаданныеТипаРеквизита = ЗначениеПоУмолчанию.Метаданные();
				ЕстьМетаданныеРеквизита = Истина;
			Исключение
			КонецПопытки;
			
			Если Не ЕстьМетаданныеРеквизита И Режим = "ПРЕДОПРЕДЕЛЕННЫЙ" Тогда
				Если БизнесПроцессы.ТипВсеСсылкиТочекМаршрутаБизнесПроцессов().СодержитТип( ТипЗначения.Типы()[0] ) Тогда
					Значение = ПолучитьЗначениеТочкиБизнесПроцесса(стрПоле.Значение);
					УжеВычислилиЗначение = Истина;
				Иначе
					Значение = Неопределено;
					СтрокаДляВыполнения = "Значение = "+ТипЗначения+"["""+стрПоле.Значение+"""];";
					Выполнить(СтрокаДляВыполнения);
					УжеВычислилиЗначение = Истина;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		Если Не УжеВычислилиЗначение и ЕстьМетаданныеРеквизита Тогда
			ПолноеИмяТипаРеквизита = МетаданныеТипаРеквизита.ПолноеИмя();
			
			Если Найти(ПолноеИмяТипаРеквизита, "Справочник") = 1 Тогда
				менеджерОбъекта = Справочники[МетаданныеТипаРеквизита.Имя];
			ИначеЕсли Найти(ПолноеИмяТипаРеквизита, "Документ") = 1 Тогда
				менеджерОбъекта = Документы[МетаданныеТипаРеквизита.Имя];
			ИначеЕсли Найти(ПолноеИмяТипаРеквизита, "Перечисление") = 1 Тогда
				менеджерОбъекта = Перечисления[МетаданныеТипаРеквизита.Имя];
			ИначеЕсли Найти(ПолноеИмяТипаРеквизита, "ПланСчетов") = 1 Тогда
				менеджерОбъекта = ПланыСчетов[МетаданныеТипаРеквизита.Имя];
			ИначеЕсли Найти(ПолноеИмяТипаРеквизита, "ПланВидовХарактеристик") = 1 Тогда
				менеджерОбъекта = ПланыВидовХарактеристик[МетаданныеТипаРеквизита.Имя];
			ИначеЕсли Найти(ПолноеИмяТипаРеквизита, "ПланВидовРасчета") = 1 Тогда //pautov
				менеджерОбъекта = ПланыВидовРасчета[МетаданныеТипаРеквизита.Имя];
			КонецЕсли;
			ПроверитьНеРавенство(менеджерОбъекта, Неопределено, "не найден менеджерОбъекта");
			
			Если Режим = "ПРЕДОПРЕДЕЛЕННЫЙ" Тогда
				//Значение = менеджерОбъекта[стрПоле.Значение];
				Если ЗначениеЗаполнено(стрПоле.Значение) Тогда
					Значение = менеджерОбъекта[стрПоле.Значение];
				Иначе
					Значение = менеджерОбъекта.ПустаяСсылка();
				КонецЕсли;
			ИначеЕсли Режим = "КОД" Тогда
				Значение = менеджерОбъекта.НайтиПоКоду(стрПоле.Значение);
			ИначеЕсли Режим = "НОМЕР" Тогда
				Значение = НайтиБлижайшийДокументПоНомеру(МетаданныеТипаРеквизита, стрПоле.Значение);
			ИначеЕсли Режим = "НАИМЕНОВАНИЕ" Тогда
				Значение = менеджерОбъекта.НайтиПоНаименованию(стрПоле.Значение, Истина);
			ИначеЕсли Режим = "ГУИД" Тогда
				Значение = менеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(стрПоле.Значение));
			Иначе
				ВызватьИсключение "НеверныйРежимПоиска: Не поддерживаемый режим поиска. Реквизит <"+стрПоле.Имя+">: Искали значение <"+стрПоле.Значение+">";
			КонецЕсли;
			
			Если ЗначениеЗаполнено(стрПоле.Значение) И Не ЗначениеЗаполнено(Значение) Тогда //Если Не ЗначениеЗаполнено(Значение) Тогда
				ВызватьИсключение "ЗначениеНеНайдено: Реквизит <"+стрПоле.Имя+">: Искали значение <"+стрПоле.Значение+">, но не нашли!";
			КонецЕсли;
		КонецЕсли;
	Исключение
		ошибка = ОписаниеОшибки();
		Если Найти(ошибка, "НеверныйРежимПоиска") = 0 Тогда
			ошибка = "ОшибкаПоиска:  Реквизит <"+стрПоле.Имя+">: Искали значение <"+стрПоле.Значение+"> " + ошибка;
		КонецЕсли;
		ВызватьИсключение ошибка;
	КонецПопытки;
		
	Возврат Значение;
КонецФункции

Функция СоздатьПользователяИБ(параметры) Экспорт
	НовыйПользователь = ПользователиИнформационнойБазы.СоздатьПользователя();

	ЗаполнитьЗначенияСвойств(НовыйПользователь, параметры,, "ОсновнойИнтерфейс");
	Если ЗначениеЗаполнено(параметры.ОсновнойИнтерфейс) Тогда
		НовыйПользователь.ОсновнойИнтерфейс = Метаданные.Интерфейсы.Найти(параметры.ОсновнойИнтерфейс);
	КонецЕсли;
	Для каждого роль Из параметры.Роли Цикл
		НовыйПользователь.Роли.Добавить(роль);
	КонецЦикла;

	НовыйПользователь.Записать();  
	Возврат НовыйПользователь;
КонецФункции

Функция КолонкиМакетаДанных()
	КолонкиМакета = Новый Структура();
	СтрокаЗеро = "0";
	КолонкиМакета.Вставить("Тип", СтрокаЗеро);
	КолонкиМакета.Вставить("Вид", СтрокаЗеро);
	КолонкиМакета.Вставить("ИмяПеременной", СтрокаЗеро);
	КолонкиМакета.Вставить("ТЧ", СтрокаЗеро);
	КолонкиМакета.Вставить("Реквизит", СтрокаЗеро);
	КолонкиМакета.Вставить("Значение", СтрокаЗеро);
	КолонкиМакета.Вставить("Режим", СтрокаЗеро);
	КолонкиМакета.Вставить("ДополнительныйТипЗначения", СтрокаЗеро);
	КолонкиМакета.Вставить("Ключ", СтрокаЗеро);
	Возврат КолонкиМакета;
КонецФункции

Функция ПолучитьЗначениеТочкиБизнесПроцесса(Значение_Строкой)
	Значение = Неопределено;
	Для каждого БизнесПроцессМенеджер из БизнесПроцессы Цикл
		ТочкиМаршрута = БизнесПроцессМенеджер.ТочкиМаршрута;
		Для каждого ТочкаМаршрута Из ТочкиМаршрута Цикл
			Если ВРег(ТочкаМаршрута.Имя) = ВРег(Значение_Строкой) Тогда
				Значение = ТочкаМаршрута;
				Возврат Значение;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	Возврат Значение;
КонецФункции

Функция НайтиБлижайшийДокументПоНомеру(МетаданныеДокумента, Значение_Строкой)

	ТекстЗапроса = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	Доки.Ссылка,
		|	Доки.Дата
		|ИЗ
		|	Документ."+МетаданныеДокумента.Имя+" КАК Доки
		|ГДЕ
		|	Доки.Номер = &Номер
		|
		|УПОРЯДОЧИТЬ ПО
		|	Доки.Дата УБЫВ";
	Запрос = Новый Запрос(ТекстЗапроса);
	Если МетаданныеДокумента.ТипНомера = Метаданные.СвойстваОбъектов.ТипНомераДокумента.Число Тогда
		Номер = Число(Значение_Строкой);
	Иначе
		Номер = Значение_Строкой;
	КонецЕсли; 
	Запрос.УстановитьПараметр("Номер", Номер);
	
	Результат = Запрос.Выполнить();
	
	Значение = Неопределено;
	
	ВыборкаДетальныеЗаписи = Результат.Выбрать();
	Если ВыборкаДетальныеЗаписи.Следующий() Тогда
		Значение = ВыборкаДетальныеЗаписи.Ссылка;
	Иначе
		ВызватьИсключение "Не удалось найти документ по номеру <"+Значение_Строкой+">. Тип Документ."+МетаданныеДокумента.Имя;	
	КонецЕсли;

	Возврат Значение;
КонецФункции

Функция НаборРеквизитовМетаданных(КорневойТип, МетаданныеОбъекта)
	НаборМдРеквизитов = Новый Структура;
	Если КорневойТип = "Справочник" 
			или КорневойТип = "Документ" 
			или КорневойТип = "ПланВидовХарактеристик"
			или КорневойТип = "БизнесПроцесс"
			или КорневойТип = "ПланОбмена" Тогда
			
		ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.СтандартныеРеквизиты, НаборМдРеквизитов);
		ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.Реквизиты, НаборМдРеквизитов);
	ИначеЕсли КорневойТип = "Задача" Тогда
		ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.СтандартныеРеквизиты, НаборМдРеквизитов);
		ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.Реквизиты, НаборМдРеквизитов);
		ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.РеквизитыАдресации, НаборМдРеквизитов);
		
	ИначеЕсли КорневойТип = "РегистрСведений" 
		или КорневойТип = "РегистрНакопления"
		или КорневойТип = "РегистрБухгалтерии" Тогда
		
			ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.СтандартныеРеквизиты, НаборМдРеквизитов);
			ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.Измерения, НаборМдРеквизитов, КорневойТип);
			ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.Ресурсы, НаборМдРеквизитов);
			ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МетаданныеОбъекта.Реквизиты, НаборМдРеквизитов);

	Иначе
		ВызватьИсключение "Необрабатываемый корневой тип <"+КорневойТип+">";
	КонецЕсли;
	Возврат НаборМдРеквизитов;
КонецФункции

Процедура ДобавитьРеквизитыМетаданныхВНаборРеквизитов(МдРеквизиты, НаборМдРеквизитов, КорневойТип = "")
	Для каждого МдРеквизит Из МдРеквизиты Цикл
		Если КорневойТип = "РегистрБухгалтерии" И Не МдРеквизит.Балансовый Тогда
			НаборМдРеквизитов.Вставить(МдРеквизит.Имя + "Дт", МдРеквизит);
			НаборМдРеквизитов.Вставить(МдРеквизит.Имя + "Кт", МдРеквизит);
		Иначе
			НаборМдРеквизитов.Вставить(МдРеквизит.Имя, МдРеквизит);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

// }

//{ Чтение JSON файла

Функция ПолучитьИмяПараметра(ТаблицаЗначенийИзФайла,СтрокаИзФайла,СчетчикСтрок,ПозицияВСтроке)
	Стр = "";
	
	КолСимволов = СтрДлина(СтрокаИзФайла);
	Пока Истина Цикл
		ПозицияВСтроке = ПозицияВСтроке + 1;
		Если ПозицияВСтроке > КолСимволов Тогда
			Прервать;
		КонецЕсли;	 
		Символ = Сред(СтрокаИзФайла,ПозицияВСтроке,1);
		
		Если Символ = """" Тогда
			Прервать;
		КонецЕсли;	 
		
		Стр = Стр + Символ;
	КонецЦикла;
	
	Возврат Стр;
КонецФункции	

Функция ПрочитатьСтруктуруИзJSON(ТаблицаЗначенийИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат)
	СтруктураДляЗаполнения = Новый Структура;
	
	Пока Истина Цикл
		ПозицияВСтроке = 0;
		СчетчикСтрок = СчетчикСтрок + 1;
		Если СчетчикСтрок > (ТаблицаЗначенийИзФайла.Количество()-1) Тогда
			Прервать;
		КонецЕсли;	 
		
		Стр = ТаблицаЗначенийИзФайла[СчетчикСтрок].Стр;
		Если Лев(Стр,1) = "}" Тогда
			Прервать;
		КонецЕсли;	 
		
		ОбработатьСтроку(ТаблицаЗначенийИзФайла,ТаблицаЗначенийИзФайла[СчетчикСтрок].Стр,СчетчикСтрок,ПозицияВСтроке,Результат,СтруктураДляЗаполнения);
		
	КонецЦикла;
	
	
	Возврат СтруктураДляЗаполнения;
КонецФункции	

Функция ПрочитатьМассивИзJSON(ТаблицаЗначенийИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат)
	СтруктураДляЗаполнения = Новый Массив;
	
	Пока Истина Цикл
		ПозицияВСтроке = 0;
		СчетчикСтрок = СчетчикСтрок + 1;
		Если СчетчикСтрок > (ТаблицаЗначенийИзФайла.Количество()-1) Тогда
			Прервать;
		КонецЕсли;	 
		
		Стр = ТаблицаЗначенийИзФайла[СчетчикСтрок].Стр;
		Если Лев(Стр,1) = "]" Тогда
			Прервать;
		КонецЕсли;	 
		
		Если Прав(Стр,1) = "," Тогда
			Стр = Лев(Стр,СтрДлина(Стр)-1);
		КонецЕсли;	 
		
		Если Лев(Стр,1) = "{" Тогда
			Значение = ПрочитатьСтруктуруИзJSON(ТаблицаЗначенийИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат);
			СтруктураДляЗаполнения.Добавить(Значение);
			Продолжить;
		КонецЕсли;	 
		
		
		Стр = УбратьЛишниеКавычки(Стр);
		СтруктураДляЗаполнения.Добавить(Стр);
		
	КонецЦикла;
	
	
	Возврат СтруктураДляЗаполнения;
КонецФункции	

Функция ПолучитьЗначениеИзJSON(ТаблицаЗначенийИзФайла,СтрокаИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат)
	Значение = "";
	
	КолСимволов = СтрДлина(СтрокаИзФайла);
	
	//пропускаем проблелы
	Пока Истина Цикл
		ПозицияВСтроке = ПозицияВСтроке + 1;
		Если ПозицияВСтроке > КолСимволов Тогда
			Прервать;
		КонецЕсли;	 
		Символ = Сред(СтрокаИзФайла,ПозицияВСтроке,1);
		
		Если Символ = " " Тогда
			Продолжить;
		Иначе
			Прервать;
		КонецЕсли;	 
		
		
	КонецЦикла;
	
	
	//сейчас мы на первом не пустом символе
	ПозицияВСтроке = ПозицияВСтроке - 1;
	Пока Истина Цикл
		ПозицияВСтроке = ПозицияВСтроке + 1;
		Если ПозицияВСтроке > КолСимволов Тогда
			Прервать;
		КонецЕсли;	 
		Символ = Сред(СтрокаИзФайла,ПозицияВСтроке,1);
		
		
		Если Символ = "{" Тогда
			Значение = ПрочитатьСтруктуруИзJSON(ТаблицаЗначенийИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат);
			Прервать;
		КонецЕсли;	 
		
		Если Символ = "[" Тогда
			Значение = ПрочитатьМассивИзJSON(ТаблицаЗначенийИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат);
			Прервать;
		КонецЕсли;	 
		
		
		Если ПозицияВСтроке = КолСимволов Тогда // значит это последний символ в строке
			Если Символ = "," Тогда
				Продолжить;
			КонецЕсли;	 
		КонецЕсли;	 
		
		
		Значение = Значение + Символ;
		
	КонецЦикла;
	
	
	
	Значение = УбратьЛишниеКавычки(Значение);
	
	Возврат Значение;
	
КонецФункции

Функция УбратьЛишниеКавычки(Знач Значение)

	Если (Лев(Значение,1) = """") и (Прав(Значение,1) = """") Тогда
		Значение = Сред(Значение,2,СтрДлина(Значение)-2);
	КонецЕсли;	 
	
	Возврат Значение;
КонецФункции

Процедура ОбработатьСтроку(ТаблицаЗначенийИзФайла,СтрокаИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат,СтруктураДляЗаполнения)
	КолСимволов = СтрДлина(СтрокаИзФайла);
	Пока Истина Цикл
		ПозицияВСтроке = ПозицияВСтроке+1;
		Если ПозицияВСтроке > КолСимволов Тогда
			Прервать;
		КонецЕсли;	 
		Символ = Сред(СтрокаИзФайла,ПозицияВСтроке,1);
		
		Если Символ = "{" Тогда
			Если Результат = Неопределено Тогда
				Результат              = Новый Структура;
				СтруктураДляЗаполнения = Результат;
			КонецЕсли;	 
			
		ИначеЕсли Символ = "}" Тогда
			
		ИначеЕсли Символ = """" Тогда
			ТекИмя = ПолучитьИмяПараметра(ТаблицаЗначенийИзФайла,СтрокаИзФайла,СчетчикСтрок,ПозицияВСтроке);
			//Сообщить("ТекИмя="+ТекИмя);
			
			
		ИначеЕсли Символ = ":" Тогда
			//ТекЗначение = Неопределено;
			Значение = ПолучитьЗначениеИзJSON(ТаблицаЗначенийИзФайла,СтрокаИзФайла,СчетчикСтрок,ПозицияВСтроке,Результат);
			Если ТипЗнч(Значение) = Тип("Строка") Тогда
				Значение = СтрЗаменить(Значение,"'","");
			КонецЕсли;	 
			СтруктураДляЗаполнения.Вставить(ТекИмя,Значение);
			Прервать;
		Иначе
			Сообщить("Ошибка чтения JSON! Неизвестный символ " + Символ);
			Возврат;
		КонецЕсли;	 
	КонецЦикла;
КонецПроцедуры

Функция ПрочитатьСтруктуруИзJSONФайла(ИмяФайлаVBParams,ПараметрыУФ = Неопределено) Экспорт
	Результат              = Неопределено;
	СтруктураДляЗаполнения = Неопределено;
	ТекЗначение            = Неопределено;
	
	
	ТаблицаЗначенийИзФайла = Новый ТаблицаЗначений;
	ТаблицаЗначенийИзФайла.Колонки.Добавить("Стр");
	
	
	Если ПараметрыУФ = Неопределено Тогда
		ИмяФайла = ИмяФайлаVBParams;
	Иначе	
		VBParamsДвоичныеДанные = ПараметрыУФ.VBParamsДвоичныеДанные;
		ИмяФайла               = ПолучитьИмяВременногоФайла("json");
		VBParamsДвоичныеДанные.Записать(ИмяФайла);
	КонецЕсли;	 
	
	Текст = Новый ЧтениеТекста;
	Текст.Открыть(ИмяФайла,"UTF-8");
	
	ТекИмя = Неопределено;
	Пока Истина Цикл
		Стр = Текст.ПрочитатьСтроку();
		Если Стр = Неопределено Тогда
			Прервать;
		КонецЕсли;	 
		
		Стр = СокрЛП(Стр);
		Если Стр = "" Тогда
			Продолжить;
		КонецЕсли;	 
		
		
		СтрТаблицаЗначенийИзФайла     = ТаблицаЗначенийИзФайла.Добавить();
		СтрТаблицаЗначенийИзФайла.Стр = Стр;
	КонецЦикла;	
	
	Текст.Закрыть();
	
	СчетчикСтрок = -1;
	Пока Истина Цикл
		СчетчикСтрок = СчетчикСтрок + 1;
		Если СчетчикСтрок > (ТаблицаЗначенийИзФайла.Количество()-1) Тогда
			Прервать;
		КонецЕсли;	 
		
		ПозицияВСтроке = 0;
		//Сообщить("ОбработатьСтроку: " + ТаблицаЗначенийИзФайла[СчетчикСтрок].Стр);
		ОбработатьСтроку(ТаблицаЗначенийИзФайла,ТаблицаЗначенийИзФайла[СчетчикСтрок].Стр,СчетчикСтрок,ПозицияВСтроке,Результат,СтруктураДляЗаполнения);
	КонецЦикла; 
	
	
	Возврат Результат;
КонецФункции	

// }

Процедура ЗапретитьВыполнениеШагов() Экспорт
	ХостФорма = ПолучитьФорму("Форма");
	ХостФорма.ЗапретитьВыполнениеШаговФорма();
КонецПроцедуры

Процедура ПродолжитьВыполнениеШагов(ШагУпал = Ложь) Экспорт
	ХостФорма = ПолучитьФорму("Форма");
	ХостФорма.ПродолжитьВыполнениеШаговФорма(ШагУпал);
КонецПроцедуры

Процедура ОбойтиДеревоДляВнутреннегоФормата(Дерево, ТабличныйДокумент, Макет, Интервал, ПараметрыОтчетаУФ) 
	
	Для каждого СтрСтроки Из Дерево.Строки Цикл
		Секция = Неопределено;
		Сценарий = Новый Структура("имя, name, start, stop, message, status");
		Если СтрСтроки.Каталог = Истина Тогда 
			Секция = макет.ПолучитьОбласть("Заголовок");
		ИначеЕсли СтрСтроки.Фича = Истина Тогда
			Секция = макет.ПолучитьОбласть("Заголовок");
		ИначеЕсли СтрСтроки.Шаг = Истина Тогда 
			Секция = макет.ПолучитьОбласть("Шаг");
		Иначе 
			Секция = макет.ПолучитьОбласть("Заголовок");
		КонецЕсли; 
		Если СтрСтроки.Пример = Истина Тогда
			Сценарий.name     = СтрСтроки.Родитель.Родитель.Имя + " №" + (СтрСтроки.Родитель.Строки.Индекс(СтрСтроки));
		Иначе	
			Сценарий.name     = СтрСтроки.Имя;
		КонецЕсли; 
		Сценарий.Имя = Интервал + СтрСтроки.Имя;
		
		Если СтрСтроки.Статус = "Failed" И НЕ СтрСтроки.Сценарий Тогда
			ИДВМассиве                         = ПараметрыОтчетаУФ.МассивИДСтрокиДерева.Найти(СтрСтроки.Родитель.ИДСтроки);
			Если ИДВМассиве <> Неопределено Тогда 
				РезультатПрохожденияТестовСценария = ПараметрыОтчетаУФ.МассивРезультатПрохожденияТестовСценария[ИДВМассиве];
			КонецЕсли;
		КонецЕсли;
		
		Если РезультатПрохожденияТестовСценария <> Неопределено Тогда 
			Сценарий.start = РезультатПрохожденияТестовСценария.ВремяНачала;
			Сценарий.stop  = РезультатПрохожденияТестовСценария.ВремяОкончания;
			Сценарий.message = РезультатПрохожденияТестовСценария.ОписаниеОшибки;
		КонецЕсли;
		
		Секция.Параметры.Заполнить(Сценарий);
		ТабличныйДокумент.Вывести(Секция);
		Если СтрСтроки.Статус = "Failed" И НЕ СтрСтроки.Сценарий Тогда
			Секция = макет.ПолучитьОбласть("Ошибка");
			Секция.Параметры.Заполнить(Сценарий);
			ТабличныйДокумент.Вывести(Секция);		
		КонецЕсли; 

		Если СтрСтроки.Строки.Количество() > 0 Тогда 
			ТабличныйДокумент.НачатьАвтогруппировкуСтрок();
			ОбойтиДеревоДляВнутреннегоФормата(СтрСтроки, ТабличныйДокумент, Макет, Интервал + "   ", ПараметрыОтчетаУФ);
			ТабличныйДокумент.ЗакончитьАвтогруппировкуСтрок();
		КонецЕсли;
	КонецЦикла;
	
	
КонецПроцедуры

Функция ВывестиОтчетТестированияВоВнутреннемФормате(Дерево, ПараметрыОтчетаУФ) Экспорт
	
	
	ТабДок = Новый ТабличныйДокумент;
	макет = ПолучитьМакет("ОтчетТестирования");
	
	Секция = макет.ПолучитьОбласть("Заголовок");
	
	Интервал = "";
	ОбойтиДеревоДляВнутреннегоФормата(Дерево, ТабДок, Макет, Интервал + "   ", ПараметрыОтчетаУФ);
		
	ТабДок.ОтображатьСетку = Ложь;
	ТабДок.Защита = Ложь;
	ТабДок.ТолькоПросмотр = Ложь;
	ТабДок.ОтображатьЗаголовки = Ложь;
	
	Возврат ТабДок;
	
КонецФункции


Функция Шаг(Стр) Экспорт
	ХостФорма = ПолучитьФорму("Форма");
	ХостФорма.ШагФорма(Стр);
КонецФункции	


Процедура СоздатьКолонкиДерева(Дерево) Экспорт
	Дерево.Колонки.Добавить("Имя");
	Дерево.Колонки.Добавить("Статус");
	Дерево.Колонки.Добавить("ПолныйПуть");
	Дерево.Колонки.Добавить("Каталог");
	Дерево.Колонки.Добавить("Фича");
	Дерево.Колонки.Добавить("Сценарий");
	Дерево.Колонки.Добавить("ЭтоScenarioOutline");
	Дерево.Колонки.Добавить("ЭтоКонтекст");
	Дерево.Колонки.Добавить("Примеры");
	Дерево.Колонки.Добавить("ИменованныеПараметры");
	Дерево.Колонки.Добавить("Пример");
	Дерево.Колонки.Добавить("Шаг");
	Дерево.Колонки.Добавить("ЗначенияПараметров");
	Дерево.Колонки.Добавить("Снипет");
	Дерево.Колонки.Добавить("АдресСнипета");
	Дерево.Колонки.Добавить("ЭтоЧужойСнипет");
	Дерево.Колонки.Добавить("СтрокаРеальнойПроцедуры");
	
	Дерево.Колонки.Добавить("РезультатПрохожденияТестовСценария");
	
	Дерево.Колонки.Добавить("ШагСПараметрамиВТаблице");
	Дерево.Колонки.Добавить("СтрокаПараметровШагаВВидеТаблицы");
	Дерево.Колонки.Добавить("ПараметрыТаблицы");
	Дерево.Колонки.Добавить("ИмяШагаБезКлючевогоСлова");
	Дерево.Колонки.Добавить("ШагСценарий");
	Дерево.Колонки.Добавить("МассивСценариевЗащитаОтЗацикливания");
	Дерево.Колонки.Добавить("ФичаИмеетСвоюEPF");
	Дерево.Колонки.Добавить("Область");
	
	Если Дерево.Колонки.Найти("ТипКартинки") = Неопределено Тогда
		Дерево.Колонки.Добавить("ТипКартинки");
	КонецЕсли;	 
	
	
	//Дерево.Колонки.Добавить("ВремяНачала");
	//Дерево.Колонки.Добавить("ВремяОкончания");
	//Дерево.Колонки.Добавить("ОписаниеОшибки");
	
КонецПроцедуры


Функция ПреобразоватьПутьСТочкамиКНормальномуПути(ОригСтр)
	ИмяВременногоФайлаКоманда = ПолучитьИмяВременногоФайла("cmd");
	ИмяВременногоФайлаЛог     = ПолучитьИмяВременногоФайла("txt");
	
	//ИмяВременногоФайлаКоманда = "h:\commons\temp\111.cmd";
	//ИмяВременногоФайлаЛог     = "h:\commons\temp\111.txt";
	
	
	Команда = "@echo on
				|for %%f in ( """ + ОригСтр + """ ) do set fullname=%%~ff
				|echo %fullname% > " + ИмяВременногоФайлаЛог;
				
	
	//Сообщить(""+ Команда);
	
	ЗТ = Новый ЗаписьТекста(ИмяВременногоФайлаКоманда,"UTF-8",,Ложь); 
	ЗТ.ЗаписатьСтроку(Команда); 
	
	ЗТ.Закрыть();
	
	
	
	
	retCode = -1;
	ЗапуститьПриложение(ИмяВременногоФайлаКоманда,,Истина,retCode);
	
	
	Рез = ОригСтр;
	
	Текст = Новый ЧтениеТекста;
	Текст.Открыть(ИмяВременногоФайлаЛог,"UTF-8");
	
	Пока Истина Цикл
		Стр = Текст.ПрочитатьСтроку();
		Если Стр = Неопределено Тогда
			Прервать;
		КонецЕсли;	 
		
		Если СокрЛП(Стр) = "" Тогда
			Продолжить;
		КонецЕсли;	 
		
		
		Рез = СокрЛП(Стр);
		
	КонецЦикла;	
	
	Текст.Закрыть();
	
	Возврат Рез;
	
КонецФункции	


Процедура ПреобразоватьПараметрыКоторыеНачинаютсяСТочкиКНормальнымПутям(СтруктураПараметров) Экспорт
	МассивКлючей = Новый Массив;
	
	Для каждого ПараметрСборки Из СтруктураПараметров Цикл
		Если Лев(ПараметрСборки.Значение,1) = "." Тогда
			МассивКлючей.Добавить(ПараметрСборки.Ключ);
		КонецЕсли;	 
	КонецЦикла;
	
	Для каждого Ключ Из МассивКлючей Цикл
		Было  = СтруктураПараметров[Ключ];
		Стало = ПреобразоватьПутьСТочкамиКНормальномуПути(СтруктураПараметров[Ключ]);
		
		СтруктураПараметров.Вставить(Ключ,Стало);
	КонецЦикла;
КонецПроцедуры



СтатусыРезультатаТестирования = Новый Структура;
СтатусыРезультатаТестирования.Вставить("ОшибкаПроверки", "Failed");
СтатусыРезультатаТестирования.Вставить("НеизвестнаяОшибка", "Broken");
СтатусыРезультатаТестирования.Вставить("ТестПропущен", "Pending");
СтатусыРезультатаТестирования = Новый ФиксированнаяСтруктура(СтатусыРезультатаТестирования);

РезультатыСравненияТаблиц = Новый Структура;
РезультатыСравненияТаблиц.Вставить("ТаблицыСовпадают", 0);
РезультатыСравненияТаблиц.Вставить("НеСовпадаютЗначенияВЯчейкеТаблицы", 1);
РезультатыСравненияТаблиц.Вставить("РазноеКоличествоСтрок", 2);
РезультатыСравненияТаблиц.Вставить("РазличаютсяКолонки", 3);
РезультатыСравненияТаблиц = Новый ФиксированнаяСтруктура(РезультатыСравненияТаблиц);

СисИнфо = Новый СистемнаяИнформация;
ЭтоLinux = (Найти(Строка(СисИнфо.ТипПлатформы), "Linux")>0)
